diff options
| author | bors <bors@rust-lang.org> | 2022-03-30 12:28:50 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-03-30 12:28:50 +0000 |
| commit | 3e7514670db841a7f0d7656f3b13b1c8b2c11599 (patch) | |
| tree | ea65f9f3d772de91ee27bf207de8cbf7ff997e8f | |
| parent | e50ff9b4521234e56ff46f8ed0372d5cb5689654 (diff) | |
| parent | 46340f20497fd9f30e08d5c30413f6f45164da89 (diff) | |
| download | rust-3e7514670db841a7f0d7656f3b13b1c8b2c11599.tar.gz rust-3e7514670db841a7f0d7656f3b13b1c8b2c11599.zip | |
Auto merge of #94963 - lcnr:inherent-impls-std, r=oli-obk,m-ou-se
allow arbitrary inherent impls for builtin types in core Part of https://github.com/rust-lang/compiler-team/issues/487. Slightly adjusted after some talks with `@m-ou-se` about the requirements of `t-libs-api`. This adds a crate attribute `#![rustc_coherence_is_core]` which allows arbitrary impls for builtin types in core. For other library crates impls for builtin types should be avoided if possible. We do have to allow the existing stable impls however. To prevent us from accidentally adding more of these in the future, there is a second attribute `#[rustc_allow_incoherent_impl]` which has to be added to **all impl items**. This only supports impls for builtin types but can easily be extended to additional types in a future PR. This implementation does not check for overlaps in these impls. Perfectly checking that requires us to check the coherence of these incoherent impls in every crate, as two distinct dependencies may add overlapping methods. It should be easy enough to detect if it goes wrong and the attribute is only intended for use inside of std. The first two commits are mostly unrelated cleanups.
66 files changed, 703 insertions, 851 deletions
diff --git a/compiler/rustc_error_codes/src/error_codes/E0118.md b/compiler/rustc_error_codes/src/error_codes/E0118.md index 345ec341c3f..8033aa8384c 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0118.md +++ b/compiler/rustc_error_codes/src/error_codes/E0118.md @@ -4,7 +4,7 @@ enum, union, or trait object. Erroneous code example: ```compile_fail,E0118 -impl (u8, u8) { // error: no nominal type found for inherent implementation +impl fn(u8) { // error: no nominal type found for inherent implementation fn get_state(&self) -> String { // ... } @@ -20,8 +20,8 @@ trait LiveLongAndProsper { fn get_state(&self) -> String; } -// and now you can implement it on (u8, u8) -impl LiveLongAndProsper for (u8, u8) { +// and now you can implement it on fn(u8) +impl LiveLongAndProsper for fn(u8) { fn get_state(&self) -> String { "He's dead, Jim!".to_owned() } @@ -33,7 +33,7 @@ For example, `NewType` is a newtype over `Foo` in `struct NewType(Foo)`. Example: ``` -struct TypeWrapper((u8, u8)); +struct TypeWrapper(fn(u8)); impl TypeWrapper { fn get_state(&self) -> String { @@ -41,24 +41,3 @@ impl TypeWrapper { } } ``` - -Instead of defining an inherent implementation on a reference, you could also -move the reference inside the implementation: - -```compile_fail,E0118 -struct Foo; - -impl &Foo { // error: no nominal type found for inherent implementation - fn bar(self, other: Self) {} -} -``` - -becomes - -``` -struct Foo; - -impl Foo { - fn bar(&self, other: &Self) {} -} -``` diff --git a/compiler/rustc_error_codes/src/error_codes/E0390.md b/compiler/rustc_error_codes/src/error_codes/E0390.md index 7a13160d098..26a9dd331ce 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0390.md +++ b/compiler/rustc_error_codes/src/error_codes/E0390.md @@ -8,8 +8,7 @@ struct Foo { } impl *mut Foo {} -// error: only a single inherent implementation marked with -// `#[lang = "mut_ptr"]` is allowed for the `*mut T` primitive +// error: cannot define inherent `impl` for primitive types ``` This isn't allowed, but using a trait to implement a method or constant @@ -29,3 +28,24 @@ impl Bar for *mut Foo { fn bar() {} // ok! } ``` + +Instead of defining an inherent implementation on a reference, you could also +move the reference inside the implementation: + +```compile_fail,E0390 +struct Foo; + +impl &Foo { // error: no nominal type found for inherent implementation + fn bar(self, other: Self) {} +} +``` + +becomes + +``` +struct Foo; + +impl Foo { + fn bar(&self, other: &Self) {} +} +``` 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_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 7c312e1b61d..b8df1632144 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -166,36 +166,6 @@ pub fn extract(attrs: &[ast::Attribute]) -> Option<(Symbol, Span)> { language_item_table! { // Variant name, Name, Method name, Target Generic requirements; - Bool, sym::bool, bool_impl, Target::Impl, GenericRequirement::None; - Char, sym::char, char_impl, Target::Impl, GenericRequirement::None; - Str, sym::str, str_impl, Target::Impl, GenericRequirement::None; - Array, sym::array, array_impl, Target::Impl, GenericRequirement::None; - Slice, sym::slice, slice_impl, Target::Impl, GenericRequirement::None; - SliceU8, sym::slice_u8, slice_u8_impl, Target::Impl, GenericRequirement::None; - StrAlloc, sym::str_alloc, str_alloc_impl, Target::Impl, GenericRequirement::None; - SliceAlloc, sym::slice_alloc, slice_alloc_impl, Target::Impl, GenericRequirement::None; - SliceU8Alloc, sym::slice_u8_alloc, slice_u8_alloc_impl, Target::Impl, GenericRequirement::None; - ConstPtr, sym::const_ptr, const_ptr_impl, Target::Impl, GenericRequirement::None; - MutPtr, sym::mut_ptr, mut_ptr_impl, Target::Impl, GenericRequirement::None; - ConstSlicePtr, sym::const_slice_ptr, const_slice_ptr_impl, Target::Impl, GenericRequirement::None; - MutSlicePtr, sym::mut_slice_ptr, mut_slice_ptr_impl, Target::Impl, GenericRequirement::None; - I8, sym::i8, i8_impl, Target::Impl, GenericRequirement::None; - I16, sym::i16, i16_impl, Target::Impl, GenericRequirement::None; - I32, sym::i32, i32_impl, Target::Impl, GenericRequirement::None; - I64, sym::i64, i64_impl, Target::Impl, GenericRequirement::None; - I128, sym::i128, i128_impl, Target::Impl, GenericRequirement::None; - Isize, sym::isize, isize_impl, Target::Impl, GenericRequirement::None; - U8, sym::u8, u8_impl, Target::Impl, GenericRequirement::None; - U16, sym::u16, u16_impl, Target::Impl, GenericRequirement::None; - U32, sym::u32, u32_impl, Target::Impl, GenericRequirement::None; - U64, sym::u64, u64_impl, Target::Impl, GenericRequirement::None; - U128, sym::u128, u128_impl, Target::Impl, GenericRequirement::None; - Usize, sym::usize, usize_impl, Target::Impl, GenericRequirement::None; - F32, sym::f32, f32_impl, Target::Impl, GenericRequirement::None; - F64, sym::f64, f64_impl, Target::Impl, GenericRequirement::None; - F32Runtime, sym::f32_runtime, f32_runtime_impl, Target::Impl, GenericRequirement::None; - F64Runtime, sym::f64_runtime, f64_runtime_impl, Target::Impl, GenericRequirement::None; - Sized, sym::sized, sized_trait, Target::Trait, GenericRequirement::Exact(0); Unsize, sym::unsize, unsize_trait, Target::Trait, GenericRequirement::Minimum(1); /// Trait injected by `#[derive(PartialEq)]`, (i.e. "Partial EQ"). diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 2e6ce7b7040..e88ef68c722 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 introduced 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. @@ -1028,11 +1033,13 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } /// Iterates over the language items in the given crate. - fn get_lang_items(self) -> impl Iterator<Item = (DefId, usize)> + 'a { - self.root - .lang_items - .decode(self) - .map(move |(def_index, index)| (self.local_def_id(def_index), index)) + fn get_lang_items(self, tcx: TyCtxt<'tcx>) -> &'tcx [(DefId, usize)] { + tcx.arena.alloc_from_iter( + self.root + .lang_items + .decode(self) + .map(move |(def_index, index)| (self.local_def_id(def_index), index)), + ) } /// Iterates over the diagnostic items in the given crate. @@ -1327,10 +1334,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 +1345,21 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { }) } + fn get_all_incoherent_impls(self) -> impl Iterator<Item = DefId> + 'a { + self.cdata + .incoherent_impls + .values() + .flat_map(move |impls| impls.decode(self).map(move |idx| self.local_def_id(idx))) + } + + 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 +1776,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 +1793,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..70358ae0e22 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(); @@ -210,7 +223,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, tcx.arena.alloc_slice(&result) } defined_lib_features => { cdata.get_lib_features(tcx) } - defined_lang_items => { tcx.arena.alloc_from_iter(cdata.get_lang_items()) } + defined_lang_items => { cdata.get_lang_items(tcx) } diagnostic_items => { cdata.get_diagnostic_items() } missing_lang_items => { cdata.get_missing_lang_items(tcx) } @@ -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 }; } @@ -511,9 +523,12 @@ impl CStore { self.get_crate_data(cnum).get_inherent_impls() } - /// Decodes all lang items in the crate (for rustdoc). - pub fn lang_items_untracked(&self, cnum: CrateNum) -> impl Iterator<Item = DefId> + '_ { - self.get_crate_data(cnum).get_lang_items().map(|(def_id, _)| def_id) + /// Decodes all incoherent inherent impls in the crate (for rustdoc). + pub fn incoherent_impls_in_crate_untracked( + &self, + cnum: CrateNum, + ) -> impl Iterator<Item = DefId> + '_ { + self.get_crate_data(cnum).get_all_incoherent_impls() } } 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/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index 335ddeb66db..5a13216846d 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -1889,10 +1889,7 @@ impl<'tcx> Ty<'tcx> { #[inline] pub fn is_slice(self) -> bool { - match self.kind() { - RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => matches!(ty.kind(), Slice(_) | Str), - _ => false, - } + matches!(self.kind(), Slice(_)) } #[inline] 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..84dbad846dd 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -494,11 +494,9 @@ symbols! { const_panic, const_panic_fmt, const_precise_live_drops, - const_ptr, const_raw_ptr_deref, const_raw_ptr_to_usize_cast, const_refs_to_cell, - const_slice_ptr, const_trait_bound_opt_out, const_trait_impl, const_transmute, @@ -655,9 +653,7 @@ symbols! { f, f16c_target_feature, f32, - f32_runtime, f64, - f64_runtime, fabsf32, fabsf64, fadd_fast, @@ -913,8 +909,6 @@ symbols! { mul_with_overflow, must_not_suspend, must_use, - mut_ptr, - mut_slice_ptr, naked, naked_functions, name, @@ -1160,10 +1154,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, @@ -1312,11 +1308,8 @@ symbols! { sized, skip, slice, - slice_alloc, slice_len_fn, slice_patterns, - slice_u8, - slice_u8_alloc, slicing_syntax, soft, specialization, @@ -1346,7 +1339,6 @@ symbols! { stop_after_dataflow, store, str, - str_alloc, str_split_whitespace, str_trim, str_trim_end, diff --git a/compiler/rustc_typeck/src/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs index 1ca9c192096..adc284785c2 100644 --- a/compiler/rustc_typeck/src/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -78,28 +78,6 @@ pub struct NoMatchData<'tcx> { pub mode: probe::Mode, } -impl<'tcx> NoMatchData<'tcx> { - pub fn new( - static_candidates: Vec<CandidateSource>, - unsatisfied_predicates: Vec<( - ty::Predicate<'tcx>, - Option<ty::Predicate<'tcx>>, - Option<ObligationCause<'tcx>>, - )>, - out_of_scope_traits: Vec<DefId>, - lev_candidate: Option<ty::AssocItem>, - mode: probe::Mode, - ) -> Self { - NoMatchData { - static_candidates, - unsatisfied_predicates, - out_of_scope_traits, - lev_candidate, - mode, - } - } -} - // A pared down enum describing just the places from which a method // candidate can arise. Used for error reporting only. #[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)] diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index abdce9f5866..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}; @@ -427,13 +428,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty)); let ty = self.structurally_resolved_type(span, ty.value); assert!(matches!(ty.kind(), ty::Error(_))); - return Err(MethodError::NoMatch(NoMatchData::new( - Vec::new(), - Vec::new(), - Vec::new(), - None, + return Err(MethodError::NoMatch(NoMatchData { + static_candidates: Vec::new(), + unsatisfied_predicates: Vec::new(), + out_of_scope_traits: Vec::new(), + lev_candidate: None, mode, - ))); + })); } } @@ -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); } } @@ -765,7 +709,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { // fcx's fulfillment context after this probe is over. // Note: we only normalize `xform_self_ty` here since the normalization // of the return type can lead to inference results that prohibit - // valid canidates from being found, see issue #85671 + // valid candidates from being found, see issue #85671 // FIXME Postponing the normalization of the return type likely only hides a deeper bug, // which might be caused by the `param_env` itself. The clauses of the `param_env` // maybe shouldn't include `Param`s, but rather fresh variables or be canonicalized, @@ -1093,13 +1037,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { } let lev_candidate = self.probe_for_lev_candidate()?; - Err(MethodError::NoMatch(NoMatchData::new( + Err(MethodError::NoMatch(NoMatchData { static_candidates, unsatisfied_predicates, out_of_scope_traits, lev_candidate, - self.mode, - ))) + mode: self.mode, + })) } fn pick_core(&mut self) -> Option<PickResult<'tcx>> { diff --git a/compiler/rustc_typeck/src/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs index 9c3f2da5644..e1d6b5d2bd4 100644 --- a/compiler/rustc_typeck/src/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -281,25 +281,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // There are methods that are defined on the primitive types and won't be // found when exploring `all_traits`, but we also need them to be acurate on // our suggestions (#47759). - let fund_assoc = |opt_def_id: Option<DefId>| { - opt_def_id.and_then(|id| self.associated_value(id, item_name)).is_some() + let found_assoc = |ty: Ty<'tcx>| { + simplify_type(tcx, ty, TreatParams::AsPlaceholders) + .and_then(|simp| { + tcx.incoherent_impls(simp) + .iter() + .find_map(|&id| self.associated_value(id, item_name)) + }) + .is_some() }; - let lang_items = tcx.lang_items(); let found_candidate = candidates.next().is_some() - || fund_assoc(lang_items.i8_impl()) - || fund_assoc(lang_items.i16_impl()) - || fund_assoc(lang_items.i32_impl()) - || fund_assoc(lang_items.i64_impl()) - || fund_assoc(lang_items.i128_impl()) - || fund_assoc(lang_items.u8_impl()) - || fund_assoc(lang_items.u16_impl()) - || fund_assoc(lang_items.u32_impl()) - || fund_assoc(lang_items.u64_impl()) - || fund_assoc(lang_items.u128_impl()) - || fund_assoc(lang_items.f32_impl()) - || fund_assoc(lang_items.f32_runtime_impl()) - || fund_assoc(lang_items.f64_impl()) - || fund_assoc(lang_items.f64_runtime_impl()); + || found_assoc(tcx.types.i8) + || found_assoc(tcx.types.i16) + || found_assoc(tcx.types.i32) + || found_assoc(tcx.types.i64) + || found_assoc(tcx.types.i128) + || found_assoc(tcx.types.u8) + || found_assoc(tcx.types.u16) + || found_assoc(tcx.types.u32) + || found_assoc(tcx.types.u64) + || found_assoc(tcx.types.u128) + || found_assoc(tcx.types.f32) + || found_assoc(tcx.types.f32); if let (true, false, SelfSource::MethodCall(expr), true) = ( actual.is_numeric(), actual.has_concrete_skeleton(), diff --git a/compiler/rustc_typeck/src/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs index 303ec910a9f..e11bd9355eb 100644 --- a/compiler/rustc_typeck/src/coherence/inherent_impls.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs @@ -7,12 +7,13 @@ //! `tcx.inherent_impls(def_id)`). That value, however, //! is computed by selecting an idea from this table. -use rustc_errors::{pluralize, struct_span_err}; +use rustc_errors::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,276 +74,19 @@ 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::Error(_) => {} - _ => { + 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::FnPtr(_) | ty::Projection(..) | ty::Opaque(..) | ty::Param(_) => { let mut err = struct_span_err!( self.tcx.sess, ty.span, @@ -347,16 +97,18 @@ impl<'tcx> ItemLikeVisitor<'_> for InherentCollect<'tcx> { err.span_label(ty.span, "impl requires a nominal type") .note("either implement a trait on it or create a newtype to wrap it instead"); - if let ty::Ref(_, subty, _) = self_ty.kind() { - err.note(&format!( - "you could also try moving the reference to \ - uses of `{}` (such as `self`) within the implementation", - subty - )); - } - err.emit(); } + ty::FnDef(..) + | ty::Closure(..) + | ty::Generator(..) + | ty::GeneratorWitness(..) + | ty::Bound(..) + | ty::Placeholder(_) + | ty::Infer(_) => { + bug!("unexpected impl self type of impl: {:?} {:?}", item.def_id, self_ty); + } + ty::Error(_) => {} } } @@ -390,60 +142,58 @@ 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!( + 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() { + if self.tcx.features().rustc_attrs { + for item in items { + if !self + .tcx + .has_attr(item.id.def_id.to_def_id(), sym::rustc_allow_incoherent_impl) + { + struct_span_err!( + self.tcx.sess, + span, + E0390, + "cannot define inherent `impl` for primitive types outside of `core`", + ) + .help(INTO_CORE) + .span_help(item.span, ADD_ATTR) + .emit(); + return; + } + } + } else { + let mut err = 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(); + "cannot define inherent `impl` for primitive types", + ); + err.help("consider using an extension trait instead"); + if let ty::Ref(_, subty, _) = ty.kind() { + err.note(&format!( + "you could also try moving the reference to \ + uses of `{}` (such as `self`) within the implementation", + subty + )); + } + err.emit(); + return; } } + + if let Some(simp) = simplify_type(self.tcx, ty, TreatParams::AsPlaceholders) { + self.impls_map.incoherent_impls.entry(simp).or_default().push(impl_def_id); + } else { + bug!("unexpected primitive type: {:?}", ty); + } } } 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 31365562ddb..89d85146963 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -237,7 +237,7 @@ mod hack { } } -#[lang = "slice_alloc"] +#[cfg_attr(bootstrap, lang = "slice_alloc")] #[cfg(not(test))] impl<T> [T] { /// Sorts the slice. @@ -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 @@ -656,7 +667,7 @@ impl<T> [T] { } } -#[lang = "slice_u8_alloc"] +#[cfg_attr(bootstrap, lang = "slice_u8_alloc")] #[cfg(not(test))] impl [u8] { /// Returns a vector containing a copy of this slice where each byte @@ -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..a3c17612c3a 100644 --- a/library/alloc/src/str.rs +++ b/library/alloc/src/str.rs @@ -235,7 +235,7 @@ impl ToOwned for str { } /// Methods for string slices. -#[lang = "str_alloc"] +#[cfg_attr(bootstrap, lang = "str_alloc")] #[cfg(not(test))] impl str { /// Converts a `Box<str>` into a `Box<[u8]>` without copying or allocating. @@ -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/array/mod.rs b/library/core/src/array/mod.rs index 20dfbc6347c..9e42ab5923a 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -395,7 +395,7 @@ macro_rules! array_impl_default { array_impl_default! {32, T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T} -#[lang = "array"] +#[cfg_attr(bootstrap, lang = "array")] impl<T, const N: usize> [T; N] { /// Returns an array of the same size as `self`, with function `f` applied to each element /// in order. diff --git a/library/core/src/bool.rs b/library/core/src/bool.rs index a13593a539d..06aee3ccbaf 100644 --- a/library/core/src/bool.rs +++ b/library/core/src/bool.rs @@ -2,7 +2,7 @@ use crate::marker::Destruct; -#[lang = "bool"] +#[cfg_attr(bootstrap, lang = "bool")] impl bool { /// Returns `Some(t)` if the `bool` is [`true`](../std/keyword.true.html), /// or `None` otherwise. diff --git a/library/core/src/char/methods.rs b/library/core/src/char/methods.rs index f75cd74ee2d..7deb3358c95 100644 --- a/library/core/src/char/methods.rs +++ b/library/core/src/char/methods.rs @@ -7,7 +7,7 @@ use crate::unicode::{self, conversions}; use super::*; -#[lang = "char"] +#[cfg_attr(bootstrap, lang = "char")] impl char { /// The highest valid code point a `char` can have, `'\u{10FFFF}'`. /// 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/core/src/num/f32.rs b/library/core/src/num/f32.rs index d8dcfdafa8d..17ca8547685 100644 --- a/library/core/src/num/f32.rs +++ b/library/core/src/num/f32.rs @@ -370,7 +370,7 @@ pub mod consts { pub const LN_10: f32 = 2.30258509299404568401799145468436421_f32; } -#[lang = "f32"] +#[cfg_attr(bootstrap, lang = "f32")] #[cfg(not(test))] impl f32 { /// The radix or base of the internal representation of `f32`. diff --git a/library/core/src/num/f64.rs b/library/core/src/num/f64.rs index 7c2f51ff646..350d8529de5 100644 --- a/library/core/src/num/f64.rs +++ b/library/core/src/num/f64.rs @@ -370,7 +370,7 @@ pub mod consts { pub const LN_10: f64 = 2.30258509299404568401799145468436421_f64; } -#[lang = "f64"] +#[cfg_attr(bootstrap, lang = "f64")] #[cfg(not(test))] impl f64 { /// The radix or base of the internal representation of `f64`. diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index c09f642d969..f4f1d274d10 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -193,26 +193,26 @@ macro_rules! widening_impl { }; } -#[lang = "i8"] +#[cfg_attr(bootstrap, lang = "i8")] impl i8 { int_impl! { i8, i8, u8, 8, 7, -128, 127, 2, "-0x7e", "0xa", "0x12", "0x12", "0x48", "[0x12]", "[0x12]", "", "" } } -#[lang = "i16"] +#[cfg_attr(bootstrap, lang = "i16")] impl i16 { int_impl! { i16, i16, u16, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } } -#[lang = "i32"] +#[cfg_attr(bootstrap, lang = "i32")] impl i32 { int_impl! { i32, i32, u32, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" } } -#[lang = "i64"] +#[cfg_attr(bootstrap, lang = "i64")] impl i64 { int_impl! { i64, i64, u64, 64, 63, -9223372036854775808, 9223372036854775807, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", @@ -220,7 +220,7 @@ impl i64 { "[0x12, 0x34, 0x56, 0x78, 0x90, 0x12, 0x34, 0x56]", "", "" } } -#[lang = "i128"] +#[cfg_attr(bootstrap, lang = "i128")] impl i128 { int_impl! { i128, i128, u128, 128, 127, -170141183460469231731687303715884105728, 170141183460469231731687303715884105727, 16, @@ -233,7 +233,7 @@ impl i128 { } #[cfg(target_pointer_width = "16")] -#[lang = "isize"] +#[cfg_attr(bootstrap, lang = "isize")] impl isize { int_impl! { isize, i16, usize, 16, 15, -32768, 32767, 4, "-0x5ffd", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", @@ -241,7 +241,7 @@ impl isize { } #[cfg(target_pointer_width = "32")] -#[lang = "isize"] +#[cfg_attr(bootstrap, lang = "isize")] impl isize { int_impl! { isize, i32, usize, 32, 31, -2147483648, 2147483647, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", @@ -250,7 +250,7 @@ impl isize { } #[cfg(target_pointer_width = "64")] -#[lang = "isize"] +#[cfg_attr(bootstrap, lang = "isize")] impl isize { int_impl! { isize, i64, usize, 64, 63, -9223372036854775808, 9223372036854775807, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", @@ -262,7 +262,7 @@ impl isize { /// If 6th bit set ascii is upper case. const ASCII_CASE_MASK: u8 = 0b0010_0000; -#[lang = "u8"] +#[cfg_attr(bootstrap, lang = "u8")] impl u8 { uint_impl! { u8, u8, i8, NonZeroU8, 8, 255, 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]", "[0x12]", "", "" } @@ -816,7 +816,7 @@ impl u8 { } } -#[lang = "u16"] +#[cfg_attr(bootstrap, lang = "u16")] impl u16 { uint_impl! { u16, u16, i16, NonZeroU16, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", "", "" } @@ -848,14 +848,14 @@ impl u16 { } } -#[lang = "u32"] +#[cfg_attr(bootstrap, lang = "u32")] impl u32 { uint_impl! { u32, u32, i32, NonZeroU32, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", "", "" } widening_impl! { u32, u64, 32, unsigned } } -#[lang = "u64"] +#[cfg_attr(bootstrap, lang = "u64")] impl u64 { uint_impl! { u64, u64, i64, NonZeroU64, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", @@ -865,7 +865,7 @@ impl u64 { widening_impl! { u64, u128, 64, unsigned } } -#[lang = "u128"] +#[cfg_attr(bootstrap, lang = "u128")] impl u128 { uint_impl! { u128, u128, i128, NonZeroU128, 128, 340282366920938463463374607431768211455, 16, "0x13f40000000000000000000000004f76", "0x4f7613f4", "0x12345678901234567890123456789012", @@ -878,7 +878,7 @@ impl u128 { } #[cfg(target_pointer_width = "16")] -#[lang = "usize"] +#[cfg_attr(bootstrap, lang = "usize")] impl usize { uint_impl! { usize, u16, isize, NonZeroUsize, 16, 65535, 4, "0xa003", "0x3a", "0x1234", "0x3412", "0x2c48", "[0x34, 0x12]", "[0x12, 0x34]", @@ -886,7 +886,7 @@ impl usize { widening_impl! { usize, u32, 16, unsigned } } #[cfg(target_pointer_width = "32")] -#[lang = "usize"] +#[cfg_attr(bootstrap, lang = "usize")] impl usize { uint_impl! { usize, u32, isize, NonZeroUsize, 32, 4294967295, 8, "0x10000b3", "0xb301", "0x12345678", "0x78563412", "0x1e6a2c48", "[0x78, 0x56, 0x34, 0x12]", "[0x12, 0x34, 0x56, 0x78]", @@ -895,7 +895,7 @@ impl usize { } #[cfg(target_pointer_width = "64")] -#[lang = "usize"] +#[cfg_attr(bootstrap, lang = "usize")] impl usize { uint_impl! { usize, u64, isize, NonZeroUsize, 64, 18446744073709551615, 12, "0xaa00000000006e1", "0x6e10aa", "0x1234567890123456", "0x5634129078563412", "0x6a2c48091e6a2c48", diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index 20ee1280264..209ea5cb043 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -4,7 +4,7 @@ use crate::intrinsics; use crate::mem; use crate::slice::{self, SliceIndex}; -#[lang = "const_ptr"] +#[cfg_attr(bootstrap, lang = "const_ptr")] impl<T: ?Sized> *const T { /// Returns `true` if the pointer is null. /// @@ -1042,7 +1042,7 @@ impl<T: ?Sized> *const T { } } -#[lang = "const_slice_ptr"] +#[cfg_attr(bootstrap, lang = "const_slice_ptr")] impl<T> *const [T] { /// Returns the length of a raw slice. /// diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 54720802521..bfc89625935 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -3,7 +3,7 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics; use crate::slice::{self, SliceIndex}; -#[lang = "mut_ptr"] +#[cfg_attr(bootstrap, lang = "mut_ptr")] impl<T: ?Sized> *mut T { /// Returns `true` if the pointer is null. /// @@ -1313,7 +1313,7 @@ impl<T: ?Sized> *mut T { } } -#[lang = "mut_slice_ptr"] +#[cfg_attr(bootstrap, lang = "mut_slice_ptr")] impl<T> *mut [T] { /// Returns the length of a raw slice. /// diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs index 6c9107401fd..7c002130040 100644 --- a/library/core/src/slice/ascii.rs +++ b/library/core/src/slice/ascii.rs @@ -6,7 +6,7 @@ use crate::iter; use crate::mem; use crate::ops; -#[lang = "slice_u8"] +#[cfg_attr(bootstrap, lang = "slice_u8")] #[cfg(not(test))] impl [u8] { /// Checks if all bytes in this slice are within the ASCII range. diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 26d4fa15d0a..77bf5f9dc34 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -109,7 +109,7 @@ enum Direction { Back, } -#[lang = "slice"] +#[cfg_attr(bootstrap, lang = "slice")] #[cfg(not(test))] impl<T> [T] { /// Returns the number of elements in the slice. diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index c603420f0f8..6bfa6a5e015 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -130,7 +130,7 @@ fn slice_error_fail_rt(s: &str, begin: usize, end: usize) -> ! { ); } -#[lang = "str"] +#[cfg_attr(bootstrap, lang = "str")] #[cfg(not(test))] impl str { /// Returns the length of `self`. diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index d23f5244d88..70b5941c7c7 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -28,7 +28,7 @@ pub use core::f32::{ }; #[cfg(not(test))] -#[lang = "f32_runtime"] +#[cfg_attr(bootstrap, lang = "f32_runtime")] impl f32 { /// Returns the largest integer less than or equal to a number. /// @@ -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..b90d068ec10 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -28,7 +28,7 @@ pub use core::f64::{ }; #[cfg(not(test))] -#[lang = "f64_runtime"] +#[cfg_attr(bootstrap, lang = "f64_runtime")] impl f64 { /// Returns the largest integer less than or equal to a number. /// @@ -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) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index 957faec30e1..3e60ed2f7c4 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -1,6 +1,7 @@ use std::cell::RefCell; use std::default::Default; use std::hash::Hash; +use std::iter; use std::lazy::SyncOnceCell as OnceCell; use std::path::PathBuf; use std::rc::Rc; @@ -22,6 +23,7 @@ use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE} use rustc_hir::lang_items::LangItem; use rustc_hir::{BodyId, Mutability}; use rustc_index::vec::IndexVec; +use rustc_middle::ty::fast_reject::SimplifiedType; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::Session; use rustc_span::hygiene::MacroKind; @@ -1625,6 +1627,7 @@ crate enum PrimitiveType { Never, } +type SimplifiedTypes = FxHashMap<PrimitiveType, ArrayVec<SimplifiedType, 2>>; impl PrimitiveType { crate fn from_hir(prim: hir::PrimTy) -> PrimitiveType { use ast::{FloatTy, IntTy, UintTy}; @@ -1680,68 +1683,68 @@ impl PrimitiveType { } } - crate fn impls(&self, tcx: TyCtxt<'_>) -> &'static ArrayVec<DefId, 4> { - Self::all_impls(tcx).get(self).expect("missing impl for primitive type") - } - - crate fn all_impls(tcx: TyCtxt<'_>) -> &'static FxHashMap<PrimitiveType, ArrayVec<DefId, 4>> { - static CELL: OnceCell<FxHashMap<PrimitiveType, ArrayVec<DefId, 4>>> = OnceCell::new(); + crate fn simplified_types() -> &'static SimplifiedTypes { + use ty::fast_reject::SimplifiedTypeGen::*; + use ty::{FloatTy, IntTy, UintTy}; + use PrimitiveType::*; + static CELL: OnceCell<SimplifiedTypes> = OnceCell::new(); + let single = |x| iter::once(x).collect(); CELL.get_or_init(move || { - use self::PrimitiveType::*; - - let single = |a: Option<DefId>| a.into_iter().collect(); - let both = |a: Option<DefId>, b: Option<DefId>| -> ArrayVec<_, 4> { - a.into_iter().chain(b).collect() - }; - - let lang_items = tcx.lang_items(); map! { - Isize => single(lang_items.isize_impl()), - I8 => single(lang_items.i8_impl()), - I16 => single(lang_items.i16_impl()), - I32 => single(lang_items.i32_impl()), - I64 => single(lang_items.i64_impl()), - I128 => single(lang_items.i128_impl()), - Usize => single(lang_items.usize_impl()), - U8 => single(lang_items.u8_impl()), - U16 => single(lang_items.u16_impl()), - U32 => single(lang_items.u32_impl()), - U64 => single(lang_items.u64_impl()), - U128 => single(lang_items.u128_impl()), - F32 => both(lang_items.f32_impl(), lang_items.f32_runtime_impl()), - F64 => both(lang_items.f64_impl(), lang_items.f64_runtime_impl()), - Char => single(lang_items.char_impl()), - Bool => single(lang_items.bool_impl()), - Str => both(lang_items.str_impl(), lang_items.str_alloc_impl()), - Slice => { - lang_items - .slice_impl() - .into_iter() - .chain(lang_items.slice_u8_impl()) - .chain(lang_items.slice_alloc_impl()) - .chain(lang_items.slice_u8_alloc_impl()) - .collect() - }, - Array => single(lang_items.array_impl()), - Tuple => ArrayVec::new(), - Unit => ArrayVec::new(), - RawPointer => { - lang_items - .const_ptr_impl() - .into_iter() - .chain(lang_items.mut_ptr_impl()) - .chain(lang_items.const_slice_ptr_impl()) - .chain(lang_items.mut_slice_ptr_impl()) - .collect() - }, - Reference => ArrayVec::new(), + Isize => single(IntSimplifiedType(IntTy::Isize)), + I8 => single(IntSimplifiedType(IntTy::I8)), + I16 => single(IntSimplifiedType(IntTy::I16)), + I32 => single(IntSimplifiedType(IntTy::I32)), + I64 => single(IntSimplifiedType(IntTy::I64)), + I128 => single(IntSimplifiedType(IntTy::I128)), + Usize => single(UintSimplifiedType(UintTy::Usize)), + U8 => single(UintSimplifiedType(UintTy::U8)), + U16 => single(UintSimplifiedType(UintTy::U16)), + U32 => single(UintSimplifiedType(UintTy::U32)), + U64 => single(UintSimplifiedType(UintTy::U64)), + U128 => single(UintSimplifiedType(UintTy::U128)), + F32 => single(FloatSimplifiedType(FloatTy::F32)), + F64 => single(FloatSimplifiedType(FloatTy::F64)), + Str => single(StrSimplifiedType), + Bool => single(BoolSimplifiedType), + Char => single(CharSimplifiedType), + Array => single(ArraySimplifiedType), + Slice => single(SliceSimplifiedType), + // FIXME: If we ever add an inherent impl for tuples + // with different lengths, they won't show in rustdoc. + // + // Either manually update this arrayvec at this point + // or start with a more complex refactoring. + Tuple => [TupleSimplifiedType(2), TupleSimplifiedType(3)].into(), + Unit => single(TupleSimplifiedType(0)), + RawPointer => [PtrSimplifiedType(Mutability::Not), PtrSimplifiedType(Mutability::Mut)].into(), + Reference => [RefSimplifiedType(Mutability::Not), RefSimplifiedType(Mutability::Mut)].into(), + // FIXME: This will be wrong if we ever add inherent impls + // for function pointers. Fn => ArrayVec::new(), - Never => ArrayVec::new(), + Never => single(NeverSimplifiedType), } }) } + crate fn impls<'tcx>(&self, tcx: TyCtxt<'tcx>) -> impl Iterator<Item = DefId> + 'tcx { + Self::simplified_types() + .get(self) + .into_iter() + .flatten() + .flat_map(move |&simp| tcx.incoherent_impls(simp)) + .copied() + } + + crate fn all_impls(tcx: TyCtxt<'_>) -> impl Iterator<Item = DefId> + '_ { + Self::simplified_types() + .values() + .flatten() + .flat_map(move |&simp| tcx.incoherent_impls(simp)) + .copied() + } + crate fn as_sym(&self) -> Symbol { use PrimitiveType::*; match self { diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 656f28bfd28..00f512ded0e 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -184,7 +184,7 @@ crate fn build_deref_target_impls(cx: &mut DocContext<'_>, items: &[Item], ret: if let Some(prim) = target.primitive_type() { let _prof_timer = cx.tcx.sess.prof.generic_activity("build_primitive_inherent_impls"); - for &did in prim.impls(tcx).iter().filter(|did| !did.is_local()) { + for did in prim.impls(tcx).filter(|did| !did.is_local()) { inline::build_impl(cx, None, did, None, ret); } } else if let Type::Path { path } = target { diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 5b14aca064e..8d66021fcaa 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -467,7 +467,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { ) -> Option<(Res, ItemFragment)> { let tcx = self.cx.tcx; - prim_ty.impls(tcx).into_iter().find_map(|&impl_| { + prim_ty.impls(tcx).find_map(|impl_| { tcx.associated_items(impl_) .find_by_name_and_namespace(tcx, Ident::with_dummy_span(item_name), ns, impl_) .map(|item| { diff --git a/src/librustdoc/passes/collect_intra_doc_links/early.rs b/src/librustdoc/passes/collect_intra_doc_links/early.rs index 30636faf98c..75e952c5122 100644 --- a/src/librustdoc/passes/collect_intra_doc_links/early.rs +++ b/src/librustdoc/passes/collect_intra_doc_links/early.rs @@ -113,7 +113,8 @@ impl IntraLinkCrateLoader<'_, '_> { Vec::from_iter(self.resolver.cstore().trait_impls_in_crate_untracked(cnum)); let all_inherent_impls = Vec::from_iter(self.resolver.cstore().inherent_impls_in_crate_untracked(cnum)); - let all_lang_items = Vec::from_iter(self.resolver.cstore().lang_items_untracked(cnum)); + let all_incoherent_impls = + Vec::from_iter(self.resolver.cstore().incoherent_impls_in_crate_untracked(cnum)); // Querying traits in scope is expensive so we try to prune the impl and traits lists // using privacy, private traits and impls from other crates are never documented in @@ -137,7 +138,7 @@ impl IntraLinkCrateLoader<'_, '_> { self.add_traits_in_parent_scope(impl_def_id); } } - for def_id in all_lang_items { + for def_id in all_incoherent_impls { self.add_traits_in_parent_scope(def_id); } diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index 53280b3df13..2852c3b616d 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -45,7 +45,7 @@ crate fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> Crate // Also try to inline primitive impls from other crates. cx.tcx.sess.prof.generic_activity("build_primitive_trait_impls").run(|| { - for &def_id in PrimitiveType::all_impls(cx.tcx).values().flatten() { + for def_id in PrimitiveType::all_impls(cx.tcx) { if !def_id.is_local() { inline::build_impl(cx, None, def_id, None, &mut new_items); diff --git a/src/test/rustdoc/intra-doc/auxiliary/extern-lang-item-impl-dep.rs b/src/test/rustdoc/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs index 87ae2f096bb..d9a08cb41b8 100644 --- a/src/test/rustdoc/intra-doc/auxiliary/extern-lang-item-impl-dep.rs +++ b/src/test/rustdoc/intra-doc/auxiliary/extern-builtin-type-impl-dep.rs @@ -1,7 +1,6 @@ // no-prefer-dynamic -#![feature(lang_items)] - +#![feature(lang_items, rustc_attrs)] #![crate_type = "rlib"] #![no_std] @@ -15,9 +14,9 @@ impl core::ops::Deref for DerefsToF64 { } mod inner { - #[lang = "f64_runtime"] impl f64 { /// [f64::clone] + #[rustc_allow_incoherent_impl] pub fn method() {} } } diff --git a/src/test/rustdoc/intra-doc/auxiliary/my-core.rs b/src/test/rustdoc/intra-doc/auxiliary/my-core.rs index bb70073fc69..e22feb03ae6 100644 --- a/src/test/rustdoc/intra-doc/auxiliary/my-core.rs +++ b/src/test/rustdoc/intra-doc/auxiliary/my-core.rs @@ -1,12 +1,12 @@ -#![feature(no_core, lang_items, rustdoc_internals)] +#![feature(no_core, lang_items, rustdoc_internals, rustc_attrs)] #![no_core] +#![rustc_coherence_is_core] #![crate_type="rlib"] #[doc(primitive = "char")] /// Some char docs mod char {} -#[lang = "char"] impl char { pub fn len_utf8(self) -> usize { 42 diff --git a/src/test/rustdoc/intra-doc/extern-lang-item-impl.rs b/src/test/rustdoc/intra-doc/extern-builtin-type-impl.rs index f64f886f076..7bb1ded3f3c 100644 --- a/src/test/rustdoc/intra-doc/extern-lang-item-impl.rs +++ b/src/test/rustdoc/intra-doc/extern-builtin-type-impl.rs @@ -2,10 +2,10 @@ // comments. The doc link points to an associated item, so we check that traits in scope for that // link are populated. -// aux-build:extern-lang-item-impl-dep.rs +// aux-build:extern-builtin-type-impl-dep.rs #![no_std] -extern crate extern_lang_item_impl_dep; +extern crate extern_builtin_type_impl_dep; -pub use extern_lang_item_impl_dep::DerefsToF64; +pub use extern_builtin_type_impl_dep::DerefsToF64; diff --git a/src/test/rustdoc/intra-doc/prim-methods-local.rs b/src/test/rustdoc/intra-doc/prim-methods-local.rs index fd0b1b97c6e..79d8df04515 100644 --- a/src/test/rustdoc/intra-doc/prim-methods-local.rs +++ b/src/test/rustdoc/intra-doc/prim-methods-local.rs @@ -1,6 +1,7 @@ #![deny(rustdoc::broken_intra_doc_links)] -#![feature(no_core, lang_items, rustdoc_internals)] +#![feature(no_core, lang_items, rustc_attrs, rustdoc_internals)] #![no_core] +#![rustc_coherence_is_core] #![crate_type = "rlib"] // @has prim_methods_local/index.html @@ -12,7 +13,6 @@ #[doc(primitive = "char")] mod char {} -#[lang = "char"] impl char { pub fn len_utf8(self) -> usize { 42 diff --git a/src/test/rustdoc/intra-doc/prim-self.rs b/src/test/rustdoc/intra-doc/prim-self.rs index 7a65723d77b..de053d70f03 100644 --- a/src/test/rustdoc/intra-doc/prim-self.rs +++ b/src/test/rustdoc/intra-doc/prim-self.rs @@ -1,12 +1,12 @@ #![deny(rustdoc::broken_intra_doc_links)] +#![rustc_coherence_is_core] #![allow(incomplete_features)] // inherent_associated_types -#![feature(lang_items)] +#![feature(rustc_attrs)] #![feature(no_core)] #![feature(rustdoc_internals)] #![feature(inherent_associated_types)] #![no_core] -#[lang = "usize"] /// [Self::f] /// [Self::MAX] // @has prim_self/primitive.usize.html diff --git a/src/test/rustdoc/issue-23511.rs b/src/test/rustdoc/issue-23511.rs index 6d421f3c253..2d2a7908fb1 100644 --- a/src/test/rustdoc/issue-23511.rs +++ b/src/test/rustdoc/issue-23511.rs @@ -1,13 +1,13 @@ -#![feature(lang_items)] +#![feature(rustc_attrs)] #![feature(rustdoc_internals)] #![no_std] pub mod str { #![doc(primitive = "str")] - #[lang = "str_alloc"] impl str { // @has search-index.js foo + #[rustc_allow_incoherent_impl] pub fn foo(&self) {} } } diff --git a/src/test/ui/error-codes/E0117.rs b/src/test/ui/error-codes/E0117.rs index dbbac514801..22b48657385 100644 --- a/src/test/ui/error-codes/E0117.rs +++ b/src/test/ui/error-codes/E0117.rs @@ -1,5 +1,4 @@ impl Drop for u32 {} //~ ERROR E0117 //~| ERROR the `Drop` trait may only be implemented for structs, enums, and unions -fn main() { -} +fn main() {} diff --git a/src/test/ui/error-codes/E0118-2.rs b/src/test/ui/error-codes/E0118-2.rs deleted file mode 100644 index fe04190162a..00000000000 --- a/src/test/ui/error-codes/E0118-2.rs +++ /dev/null @@ -1,8 +0,0 @@ -struct Foo; - -impl &mut Foo { - //~^ ERROR E0118 - fn bar(self) {} -} - -fn main() {} diff --git a/src/test/ui/error-codes/E0118-2.stderr b/src/test/ui/error-codes/E0118-2.stderr deleted file mode 100644 index 2a1fe231116..00000000000 --- a/src/test/ui/error-codes/E0118-2.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0118]: no nominal type found for inherent implementation - --> $DIR/E0118-2.rs:3:6 - | -LL | impl &mut Foo { - | ^^^^^^^^ impl requires a nominal type - | - = note: either implement a trait on it or create a newtype to wrap it instead - = note: you could also try moving the reference to uses of `Foo` (such as `self`) within the implementation - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0118`. diff --git a/src/test/ui/error-codes/E0118.rs b/src/test/ui/error-codes/E0118.rs index 7bf36210f3a..aaef8113b8a 100644 --- a/src/test/ui/error-codes/E0118.rs +++ b/src/test/ui/error-codes/E0118.rs @@ -1,8 +1,7 @@ -impl (u8, u8) { //~ ERROR E0118 +impl fn(u8) { //~ ERROR E0118 fn get_state(&self) -> String { - String::new() + String::new() } } -fn main() { -} +fn main() {} diff --git a/src/test/ui/error-codes/E0118.stderr b/src/test/ui/error-codes/E0118.stderr index 2693a93213a..296fb5d664a 100644 --- a/src/test/ui/error-codes/E0118.stderr +++ b/src/test/ui/error-codes/E0118.stderr @@ -1,8 +1,8 @@ error[E0118]: no nominal type found for inherent implementation --> $DIR/E0118.rs:1:6 | -LL | impl (u8, u8) { - | ^^^^^^^^ impl requires a nominal type +LL | impl fn(u8) { + | ^^^^^^ impl requires a nominal type | = note: either implement a trait on it or create a newtype to wrap it instead diff --git a/src/test/ui/error-codes/E0120.rs b/src/test/ui/error-codes/E0120.rs index 287a4088183..a0a301a06e2 100644 --- a/src/test/ui/error-codes/E0120.rs +++ b/src/test/ui/error-codes/E0120.rs @@ -5,5 +5,4 @@ impl Drop for dyn MyTrait { fn drop(&mut self) {} } -fn main() { -} +fn main() {} diff --git a/src/test/ui/error-codes/E0390.stderr b/src/test/ui/error-codes/E0390.stderr index be47e93d19a..e635d4ec196 100644 --- a/src/test/ui/error-codes/E0390.stderr +++ b/src/test/ui/error-codes/E0390.stderr @@ -1,10 +1,10 @@ -error[E0390]: only a single inherent implementation marked with `#[lang = "mut_ptr"]` is allowed for the `*mut T` primitive - --> $DIR/E0390.rs:5:1 +error[E0390]: cannot define inherent `impl` for primitive types + --> $DIR/E0390.rs:5:6 | LL | impl *mut Foo {} - | ^^^^^^^^^^^^^^^^ + | ^^^^^^^^ | - = help: consider using a trait + = help: consider using an extension trait instead error: aborting due to previous error diff --git a/src/test/ui/kinds-of-primitive-impl.rs b/src/test/ui/kinds-of-primitive-impl.rs index b045b050d77..6a067a9a360 100644 --- a/src/test/ui/kinds-of-primitive-impl.rs +++ b/src/test/ui/kinds-of-primitive-impl.rs @@ -1,20 +1,26 @@ impl u8 { -//~^ error: only a single inherent implementation marked with `#[lang = "u8"]` is allowed for the `u8` primitive +//~^ error: cannot define inherent `impl` for primitive types pub const B: u8 = 0; } impl str { -//~^ error: only a single inherent implementation marked with `#[lang = "str"]` is allowed for the `str` primitive +//~^ error: cannot define inherent `impl` for primitive types fn foo() {} fn bar(self) {} } impl char { -//~^ error: only a single inherent implementation marked with `#[lang = "char"]` is allowed for the `char` primitive +//~^ error: cannot define inherent `impl` for primitive types pub const B: u8 = 0; pub const C: u8 = 0; fn foo() {} fn bar(self) {} } +struct MyType; +impl &MyType { +//~^ error: cannot define inherent `impl` for primitive types + pub fn for_ref(self) {} +} + fn main() {} diff --git a/src/test/ui/kinds-of-primitive-impl.stderr b/src/test/ui/kinds-of-primitive-impl.stderr index f1fb2953083..f4dbd1c40e8 100644 --- a/src/test/ui/kinds-of-primitive-impl.stderr +++ b/src/test/ui/kinds-of-primitive-impl.stderr @@ -1,40 +1,36 @@ -error[E0390]: only a single inherent implementation marked with `#[lang = "u8"]` is allowed for the `u8` primitive - --> $DIR/kinds-of-primitive-impl.rs:1:1 +error[E0390]: cannot define inherent `impl` for primitive types + --> $DIR/kinds-of-primitive-impl.rs:1:6 | -LL | / impl u8 { -LL | | -LL | | pub const B: u8 = 0; -LL | | } - | |_^ +LL | impl u8 { + | ^^ | - = help: consider using a trait to implement this constant + = help: consider using an extension trait instead -error[E0390]: only a single inherent implementation marked with `#[lang = "str"]` is allowed for the `str` primitive - --> $DIR/kinds-of-primitive-impl.rs:6:1 +error[E0390]: cannot define inherent `impl` for primitive types + --> $DIR/kinds-of-primitive-impl.rs:6:6 | -LL | / impl str { -LL | | -LL | | fn foo() {} -LL | | fn bar(self) {} -LL | | } - | |_^ +LL | impl str { + | ^^^ | - = help: consider using a trait to implement these methods + = help: consider using an extension trait instead -error[E0390]: only a single inherent implementation marked with `#[lang = "char"]` is allowed for the `char` primitive - --> $DIR/kinds-of-primitive-impl.rs:12:1 - | -LL | / impl char { -LL | | -LL | | pub const B: u8 = 0; -LL | | pub const C: u8 = 0; -LL | | fn foo() {} -LL | | fn bar(self) {} -LL | | } - | |_^ - | - = help: consider using a trait to implement these associated items +error[E0390]: cannot define inherent `impl` for primitive types + --> $DIR/kinds-of-primitive-impl.rs:12:6 + | +LL | impl char { + | ^^^^ + | + = help: consider using an extension trait instead + +error[E0390]: cannot define inherent `impl` for primitive types + --> $DIR/kinds-of-primitive-impl.rs:21:6 + | +LL | impl &MyType { + | ^^^^^^^ + | + = help: consider using an extension trait instead + = note: you could also try moving the reference to uses of `MyType` (such as `self`) within the implementation -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0390`. diff --git a/src/test/ui/lang-items/lang-item-correct-generics.rs b/src/test/ui/lang-items/lang-item-correct-generics.rs deleted file mode 100644 index a3287db74e7..00000000000 --- a/src/test/ui/lang-items/lang-item-correct-generics.rs +++ /dev/null @@ -1,28 +0,0 @@ -// build-pass - -#![feature(lang_items,no_core)] -#![no_core] -#![crate_type="lib"] - -#[lang = "sized"] -trait MySized {} - -#[lang = "copy"] -trait MyCopy {} - -#[lang = "drop"] -trait MyDrop<T> {} - -struct S; - -impl<T> MyDrop<T> for S {} - -#[lang = "i32"] -impl<'a> i32 { - fn foo() {} -} - -fn bar() { - i32::foo(); - S; -} diff --git a/src/test/ui/single-primitive-inherent-impl.rs b/src/test/ui/single-primitive-inherent-impl.rs deleted file mode 100644 index 75c62feec32..00000000000 --- a/src/test/ui/single-primitive-inherent-impl.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![crate_type = "lib"] -#![feature(lang_items)] -#![no_std] - -// OK -#[lang = "str_alloc"] -impl str {} - -impl str { -//~^ error: only a single inherent implementation marked with `#[lang = "str"]` is allowed for the `str` primitive -} diff --git a/src/test/ui/single-primitive-inherent-impl.stderr b/src/test/ui/single-primitive-inherent-impl.stderr deleted file mode 100644 index 349a12eac05..00000000000 --- a/src/test/ui/single-primitive-inherent-impl.stderr +++ /dev/null @@ -1,13 +0,0 @@ -error[E0390]: only a single inherent implementation marked with `#[lang = "str"]` is allowed for the `str` primitive - --> $DIR/single-primitive-inherent-impl.rs:9:1 - | -LL | / impl str { -LL | | -LL | | } - | |_^ - | - = help: consider using a trait - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0390`. diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs index 6515975fbff..ae4158662d4 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs @@ -3,7 +3,7 @@ use clippy_utils::{higher, peel_blocks_with_stmt, SpanlessEq}; use if_chain::if_chain; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; -use rustc_hir::{lang_items::LangItem, BinOpKind, Expr, ExprKind, QPath}; +use rustc_hir::{BinOpKind, Expr, ExprKind, QPath}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; @@ -82,14 +82,6 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { // Get the variable name let var_name = ares_path.segments[0].ident.name.as_str(); - const INT_TYPES: [LangItem; 5] = [ - LangItem::I8, - LangItem::I16, - LangItem::I32, - LangItem::I64, - LangItem::Isize - ]; - match cond_num_val.kind { ExprKind::Lit(ref cond_lit) => { // Check if the constant is zero @@ -105,8 +97,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { if name.ident.as_str() == "MIN"; if let Some(const_id) = cx.typeck_results().type_dependent_def_id(cond_num_val.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(const_id); - let mut int_ids = INT_TYPES.iter().filter_map(|&ty| cx.tcx.lang_items().require(ty).ok()); - if int_ids.any(|int_id| int_id == impl_id); + if let None = cx.tcx.impl_trait_ref(impl_id); // An inherent impl + if cx.tcx.type_of(impl_id).is_integral(); then { print_lint_and_sugg(cx, var_name, expr) } @@ -118,8 +110,8 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { if name.ident.as_str() == "min_value"; if let Some(func_id) = cx.typeck_results().type_dependent_def_id(func.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(func_id); - let mut int_ids = INT_TYPES.iter().filter_map(|&ty| cx.tcx.lang_items().require(ty).ok()); - if int_ids.any(|int_id| int_id == impl_id); + if let None = cx.tcx.impl_trait_ref(impl_id); // An inherent impl + if cx.tcx.type_of(impl_id).is_integral(); then { print_lint_and_sugg(cx, var_name, expr) } diff --git a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs index 6e64e7f6222..c98cdfbca43 100644 --- a/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs +++ b/src/tools/clippy/clippy_lints/src/methods/implicit_clone.rs @@ -49,10 +49,11 @@ pub fn is_clone_like(cx: &LateContext<'_>, method_name: &str, method_def_id: hir "to_owned" => is_diag_trait_item(cx, method_def_id, sym::ToOwned), "to_path_buf" => is_diag_item_method(cx, method_def_id, sym::Path), "to_vec" => { - cx.tcx - .impl_of_method(method_def_id) - .map(|impl_did| Some(impl_did) == cx.tcx.lang_items().slice_alloc_impl()) - == Some(true) + cx.tcx.impl_of_method(method_def_id) + .filter(|&impl_did| { + cx.tcx.type_of(impl_did).is_slice() && cx.tcx.impl_trait_ref(impl_did).is_none() + }) + .is_some() }, _ => false, } diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs index 1c546a15bf6..55567d8625e 100644 --- a/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_splitn.rs @@ -12,13 +12,13 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se if count <= 1; if let Some(call_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id); if let Some(impl_id) = cx.tcx.impl_of_method(call_id); - let lang_items = cx.tcx.lang_items(); - if lang_items.slice_impl() == Some(impl_id) || lang_items.str_impl() == Some(impl_id); + if cx.tcx.impl_trait_ref(impl_id).is_none(); + let self_ty = cx.tcx.type_of(impl_id); + if self_ty.is_slice() || self_ty.is_str(); then { // Ignore empty slice and string literals when used with a literal count. if matches!(self_arg.kind, ExprKind::Array([])) || matches!(self_arg.kind, ExprKind::Lit(Spanned { node: LitKind::Str(s, _), .. }) if s.is_empty()) - { return; } @@ -28,7 +28,7 @@ pub(super) fn check(cx: &LateContext<'_>, method_name: &str, expr: &Expr<'_>, se "the resulting iterator will always return `None`") } else { (format!("`{}` called with `1` split", method_name), - if lang_items.slice_impl() == Some(impl_id) { + if self_ty.is_slice() { "the resulting iterator will always return the entire slice followed by `None`" } else { "the resulting iterator will always return the entire string followed by `None`" diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs index ba1997e70e1..9d4313827f7 100644 --- a/src/tools/clippy/clippy_lints/src/ptr.rs +++ b/src/tools/clippy/clippy_lints/src/ptr.rs @@ -16,7 +16,7 @@ use rustc_hir::{ }; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::{self, AssocItems, AssocKind, Ty}; +use rustc_middle::ty::{self, Ty}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::source_map::Span; use rustc_span::symbol::Symbol; @@ -308,7 +308,6 @@ struct PtrArg<'tcx> { method_renames: &'static [(&'static str, &'static str)], ref_prefix: RefPrefix, deref_ty: DerefTy<'tcx>, - deref_assoc_items: Option<(DefId, &'tcx AssocItems<'tcx>)>, } impl PtrArg<'_> { fn build_msg(&self) -> String { @@ -411,7 +410,7 @@ fn check_fn_args<'cx, 'tcx: 'cx>( if params.get(i).map_or(true, |p| !is_lint_allowed(cx, PTR_ARG, p.hir_id)); then { - let (method_renames, deref_ty, deref_impl_id) = match cx.tcx.get_diagnostic_name(adt.did()) { + let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) { Some(sym::Vec) => ( [("clone", ".to_owned()")].as_slice(), DerefTy::Slice( @@ -424,17 +423,14 @@ fn check_fn_args<'cx, 'tcx: 'cx>( }), substs.type_at(0), ), - cx.tcx.lang_items().slice_impl() ), Some(sym::String) => ( [("clone", ".to_owned()"), ("as_str", "")].as_slice(), DerefTy::Str, - cx.tcx.lang_items().str_impl() ), Some(sym::PathBuf) => ( [("clone", ".to_path_buf()"), ("as_path", "")].as_slice(), DerefTy::Path, - None, ), Some(sym::Cow) if mutability == Mutability::Not => { let ty_name = name.args @@ -470,7 +466,6 @@ fn check_fn_args<'cx, 'tcx: 'cx>( mutability, }, deref_ty, - deref_assoc_items: deref_impl_id.map(|id| (id, cx.tcx.associated_items(id))), }); } } @@ -607,14 +602,7 @@ fn check_ptr_arg_usage<'tcx>(cx: &LateContext<'tcx>, body: &'tcx Body<'_>, args: // If the types match check for methods which exist on both types. e.g. `Vec::len` and // `slice::len` ty::Adt(def, _) - if def.did() == args.ty_did - && (i != 0 - || self.cx.tcx.trait_of_item(id).is_some() - || !args.deref_assoc_items.map_or(false, |(id, items)| { - items - .find_by_name_and_kind(self.cx.tcx, name.ident, AssocKind::Fn, id) - .is_some() - })) => + if def.did() == args.ty_did => { set_skip_flag(); }, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index cd20abd94ed..62e14439801 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -77,9 +77,9 @@ use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk}; use rustc_hir::{ - def, lang_items, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, + def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Constness, Destination, Expr, ExprKind, FnDecl, ForeignItem, HirId, Impl, ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, - MatchSource, Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, Target, + MatchSource, Mutability, Node, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind, UnOp, }; use rustc_lint::{LateContext, Level, Lint, LintContext}; @@ -87,6 +87,8 @@ use rustc_middle::hir::place::PlaceBase; use rustc_middle::ty as rustc_ty; use rustc_middle::ty::adjustment::{Adjust, Adjustment, AutoBorrow}; use rustc_middle::ty::binding::BindingMode; +use rustc_middle::ty::{IntTy, UintTy, FloatTy}; +use rustc_middle::ty::fast_reject::SimplifiedTypeGen::*; use rustc_middle::ty::{layout::IntegerExt, BorrowKind, DefIdTree, Ty, TyCtxt, TypeAndMut, TypeFoldable, UpvarCapture}; use rustc_semver::RustcVersion; use rustc_session::Session; @@ -455,14 +457,6 @@ pub fn path_def_id<'tcx>(cx: &LateContext<'_>, maybe_path: &impl MaybePath<'tcx> /// Resolves a def path like `std::vec::Vec`. /// This function is expensive and should be used sparingly. pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { - macro_rules! try_res { - ($e:expr) => { - match $e { - Some(e) => e, - None => return Res::Err, - } - }; - } fn item_child_by_name(tcx: TyCtxt<'_>, def_id: DefId, name: &str) -> Option<Res> { match tcx.def_kind(def_id) { DefKind::Mod | DefKind::Enum | DefKind::Trait => tcx @@ -479,11 +473,35 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { _ => None, } } - fn find_primitive(tcx: TyCtxt<'_>, name: &str) -> Option<DefId> { - if let Some(&(index, Target::Impl)) = lang_items::ITEM_REFS.get(&Symbol::intern(name)) { - tcx.lang_items().items()[index] - } else { - None + fn find_primitive<'tcx>(tcx: TyCtxt<'tcx>, name: &str) -> impl Iterator<Item = DefId> + 'tcx { + let single = |ty| tcx.incoherent_impls(ty).iter().copied(); + let empty = || [].iter().copied(); + match name { + "bool" => single(BoolSimplifiedType), + "char" => single(CharSimplifiedType), + "str" => single(StrSimplifiedType), + "array" => single(ArraySimplifiedType), + "slice" => single(SliceSimplifiedType), + // FIXME: rustdoc documents these two using just `pointer`. + // + // Maybe this is something we should do here too. + "const_ptr" => single(PtrSimplifiedType(Mutability::Not)), + "mut_ptr" => single(PtrSimplifiedType(Mutability::Mut)), + "isize" => single(IntSimplifiedType(IntTy::Isize)), + "i8" => single(IntSimplifiedType(IntTy::I8)), + "i16" => single(IntSimplifiedType(IntTy::I16)), + "i32" => single(IntSimplifiedType(IntTy::I32)), + "i64" => single(IntSimplifiedType(IntTy::I64)), + "i128" => single(IntSimplifiedType(IntTy::I128)), + "usize" => single(UintSimplifiedType(UintTy::Usize)), + "u8" => single(UintSimplifiedType(UintTy::U8)), + "u16" => single(UintSimplifiedType(UintTy::U16)), + "u32" => single(UintSimplifiedType(UintTy::U32)), + "u64" => single(UintSimplifiedType(UintTy::U64)), + "u128" => single(UintSimplifiedType(UintTy::U128)), + "f32" => single(FloatSimplifiedType(FloatTy::F32)), + "f64" => single(FloatSimplifiedType(FloatTy::F64)), + _ => empty(), } } fn find_crate(tcx: TyCtxt<'_>, name: &str) -> Option<DefId> { @@ -502,30 +520,35 @@ pub fn def_path_res(cx: &LateContext<'_>, path: &[&str]) -> Res { _ => return Res::Err, }; let tcx = cx.tcx; - let first = try_res!( - find_primitive(tcx, base) - .or_else(|| find_crate(tcx, base)) - .and_then(|id| item_child_by_name(tcx, id, first)) - ); + let starts = find_primitive(tcx, base) + .chain(find_crate(tcx, base)) + .flat_map(|id| item_child_by_name(tcx, id, first)); - let last = path - .iter() - .copied() - // for each segment, find the child item - .try_fold(first, |res, segment| { - let def_id = res.def_id(); - if let Some(item) = item_child_by_name(tcx, def_id, segment) { - Some(item) - } else if matches!(res, Res::Def(DefKind::Enum | DefKind::Struct, _)) { - // it is not a child item so check inherent impl items - tcx.inherent_impls(def_id) - .iter() - .find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment)) - } else { - None - } - }); - try_res!(last).expect_non_local() + for first in starts { + let last = path + .iter() + .copied() + // for each segment, find the child item + .try_fold(first, |res, segment| { + let def_id = res.def_id(); + if let Some(item) = item_child_by_name(tcx, def_id, segment) { + Some(item) + } else if matches!(res, Res::Def(DefKind::Enum | DefKind::Struct, _)) { + // it is not a child item so check inherent impl items + tcx.inherent_impls(def_id) + .iter() + .find_map(|&impl_def_id| item_child_by_name(tcx, impl_def_id, segment)) + } else { + None + } + }); + + if let Some(last) = last { + return last; + } + } + + Res::Err } /// Convenience function to get the `DefId` of a trait by path. |
