diff --git a/compiler/rustc_codegen_gcc/src/attributes.rs b/compiler/rustc_codegen_gcc/src/attributes.rs index 27f21107eda70..3a64eaf0b47ef 100644 --- a/compiler/rustc_codegen_gcc/src/attributes.rs +++ b/compiler/rustc_codegen_gcc/src/attributes.rs @@ -47,7 +47,7 @@ pub fn from_fn_attrs<'gcc, 'tcx>( let inline = if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::NAKED) { InlineAttr::Never } else if codegen_fn_attrs.inline == InlineAttr::None - && instance.def.requires_inline(cx.tcx) + && cx.tcx.cross_crate_inlinable(instance.def_id()) { InlineAttr::Hint } else { diff --git a/compiler/rustc_codegen_llvm/src/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs index 3877460fcdb0d..4d05260d4e494 100644 --- a/compiler/rustc_codegen_llvm/src/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -348,12 +348,13 @@ pub fn from_fn_attrs<'ll, 'tcx>( OptimizeAttr::Speed => {} } - let inline = - if codegen_fn_attrs.inline == InlineAttr::None && instance.def.requires_inline(cx.tcx) { - InlineAttr::Hint - } else { - codegen_fn_attrs.inline - }; + let inline = if codegen_fn_attrs.inline == InlineAttr::None + && cx.tcx.cross_crate_inlinable(instance.def_id()) + { + InlineAttr::Hint + } else { + codegen_fn_attrs.inline + }; to_add.extend(inline_attr(cx, inline)); // The `uwtable` attribute according to LLVM is: diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs index b7ad09b055a95..c8536946fdd92 100644 --- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs +++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs @@ -98,9 +98,7 @@ fn reachable_non_generics_provider(tcx: TyCtxt<'_>, _: LocalCrate) -> DefIdMap CrateMetadataRef<'a> { } fn cross_crate_inlinable(self, id: DefIndex) -> bool { - self.root.tables.cross_crate_inlinable.get(self, id) + self.root.tables.cross_crate_inlinable.get(self, id).unwrap_or_else(|| { + debug!("cross_crate_inlinable missing for {id:?}"); + false + }) } fn get_fn_has_self_parameter(self, id: DefIndex, sess: &'a Session) -> bool { diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 6f31c0fa52027..8ad0000ef97a0 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1656,19 +1656,50 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let tcx = self.tcx; let reachable_set = tcx.reachable_set(()); - let keys_and_jobs = tcx.mir_keys(()).iter().filter_map(|&def_id| { + let lang_items = tcx.lang_items(); + for (trait_def_id, symbol) in [ + (lang_items.clone_trait(), sym::clone), + (lang_items.fn_once_trait(), sym::call_once), + (lang_items.fn_mut_trait(), sym::call_mut), + (lang_items.fn_trait(), sym::call), + ] { + if let Some(trait_def_id) = trait_def_id { + let fn_def_id = tcx + .associated_items(trait_def_id) + .filter_by_name_unhygienic(symbol) + .next() + .unwrap() + .def_id; + if fn_def_id.is_local() { + self.tables + .cross_crate_inlinable + .set(fn_def_id.index, Some(self.tcx.cross_crate_inlinable(fn_def_id))); + } + } + } + + for (symbol, _) in tcx.exported_symbols(LOCAL_CRATE) { + use crate::rmeta::ExportedSymbol::*; + let (NonGeneric(def_id) | Generic(def_id, _) | ThreadLocalShim(def_id)) = symbol else { + continue; + }; + self.tables.cross_crate_inlinable.set(def_id.index, Some(false)); + } + + for def_id in tcx.mir_keys(()).iter().copied() { + self.tables + .cross_crate_inlinable + .set(def_id.to_def_id().index, Some(self.tcx.cross_crate_inlinable(def_id))); let (encode_const, encode_opt) = should_encode_mir(tcx, reachable_set, def_id); - if encode_const || encode_opt { Some((def_id, encode_const, encode_opt)) } else { None } - }); - for (def_id, encode_const, encode_opt) in keys_and_jobs { + if encode_const || encode_opt { + } else { + continue; + } debug_assert!(encode_const || encode_opt); debug!("EntryBuilder::encode_mir({:?})", def_id); if encode_opt { record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id)); - self.tables - .cross_crate_inlinable - .set(def_id.to_def_id().index, self.tcx.cross_crate_inlinable(def_id)); record!(self.tables.closure_saved_names_of_captured_variables[def_id.to_def_id()] <- tcx.closure_saved_names_of_captured_variables(def_id)); @@ -1710,6 +1741,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tables.unused_generic_params.set(def_id.local_def_index, unused); } + if let Some(def_id) = tcx.lang_items().drop_in_place_fn() { + self.tables.cross_crate_inlinable.set(def_id.index, Some(false)); + } + // Encode all the deduced parameter attributes for everything that has MIR, even for items // that can't be inlined. But don't if we aren't optimizing in non-incremental mode, to // save the query traffic. diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index e565c8c1ea1c9..e632859798549 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -400,7 +400,7 @@ define_tables! { // That's why the encoded list needs to contain `ModChild` structures describing all the names // individually instead of `DefId`s. module_children_reexports: Table>, - cross_crate_inlinable: Table, + cross_crate_inlinable: Table>, - optional: attributes: Table>, diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs index 146cd6dfbeb7e..0404453804ef0 100644 --- a/compiler/rustc_middle/src/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -1,6 +1,5 @@ use crate::dep_graph::{DepNode, WorkProduct, WorkProductId}; use crate::ty::{GenericArgs, Instance, InstanceKind, SymbolName, TyCtxt}; -use rustc_attr::InlineAttr; use rustc_data_structures::base_n::BaseNString; use rustc_data_structures::base_n::ToBaseN; use rustc_data_structures::base_n::CASE_INSENSITIVE; @@ -13,7 +12,6 @@ use rustc_hir::ItemId; use rustc_index::Idx; use rustc_macros::{HashStable, TyDecodable, TyEncodable}; use rustc_query_system::ich::StableHashingContext; -use rustc_session::config::OptLevel; use rustc_span::symbol::Symbol; use rustc_span::Span; use std::fmt; @@ -105,41 +103,23 @@ impl<'tcx> MonoItem<'tcx> { } pub fn instantiation_mode(&self, tcx: TyCtxt<'tcx>) -> InstantiationMode { - let generate_cgu_internal_copies = tcx - .sess - .opts - .unstable_opts - .inline_in_all_cgus - .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No) - && !tcx.sess.link_dead_code(); - + if tcx.sess.link_dead_code() { + return InstantiationMode::GloballyShared { may_conflict: false }; + } match *self { MonoItem::Fn(ref instance) => { let entry_def_id = tcx.entry_fn(()).map(|(id, _)| id); - // If this function isn't inlined or otherwise has an extern - // indicator, then we'll be creating a globally shared version. - if tcx.codegen_fn_attrs(instance.def_id()).contains_extern_indicator() - || !instance.def.generates_cgu_internal_copy(tcx) - || Some(instance.def_id()) == entry_def_id - { + if Some(instance.def_id()) == entry_def_id { return InstantiationMode::GloballyShared { may_conflict: false }; } - - // At this point we don't have explicit linkage and we're an - // inlined function. If we're inlining into all CGUs then we'll - // be creating a local copy per CGU. - if generate_cgu_internal_copies { - return InstantiationMode::LocalCopy; - } - - // Finally, if this is `#[inline(always)]` we're sure to respect - // that with an inline copy per CGU, but otherwise we'll be - // creating one copy of this `#[inline]` function which may - // conflict with upstream crates as it could be an exported - // symbol. - match tcx.codegen_fn_attrs(instance.def_id()).inline { - InlineAttr::Always => InstantiationMode::LocalCopy, - _ => InstantiationMode::GloballyShared { may_conflict: true }, + if tcx.cross_crate_inlinable(instance.def_id()) { + if tcx.sess.opts.incremental.is_some() { + InstantiationMode::GloballyShared { may_conflict: true } + } else { + InstantiationMode::LocalCopy + } + } else { + InstantiationMode::GloballyShared { may_conflict: false } } } MonoItem::Static(..) | MonoItem::GlobalAsm(..) => { diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index c7ea1d4338366..cb439971f5738 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -2285,7 +2285,7 @@ rustc_queries! { } query cross_crate_inlinable(def_id: DefId) -> bool { - desc { "whether the item should be made inlinable across crates" } + desc { |tcx| "deciding whether `{}` should be inlinable across crates", tcx.def_path_str(key) } separate_provide_extern } } diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs index 6e64e9bc4f87a..7f2a811e8f8c1 100644 --- a/compiler/rustc_middle/src/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -286,26 +286,6 @@ impl<'tcx> InstanceKind<'tcx> { tcx.get_attrs(self.def_id(), attr) } - /// Returns `true` if the LLVM version of this instance is unconditionally - /// marked with `inline`. This implies that a copy of this instance is - /// generated in every codegen unit. - /// Note that this is only a hint. See the documentation for - /// `generates_cgu_internal_copy` for more information. - pub fn requires_inline(&self, tcx: TyCtxt<'tcx>) -> bool { - use rustc_hir::definitions::DefPathData; - let def_id = match *self { - ty::InstanceKind::Item(def) => def, - ty::InstanceKind::DropGlue(_, Some(_)) => return false, - ty::InstanceKind::AsyncDropGlueCtorShim(_, Some(_)) => return false, - ty::InstanceKind::ThreadLocalShim(_) => return false, - _ => return true, - }; - matches!( - tcx.def_key(def_id).disambiguated_data.data, - DefPathData::Ctor | DefPathData::Closure - ) - } - /// Returns `true` if the machine code for this instance is instantiated in /// each codegen unit that references it. /// Note that this is only a hint! The compiler can globally decide to *not* @@ -314,39 +294,6 @@ impl<'tcx> InstanceKind<'tcx> { /// `-Copt-level=0`) then the time for generating them is wasted and it's /// better to create a single copy with external linkage. pub fn generates_cgu_internal_copy(&self, tcx: TyCtxt<'tcx>) -> bool { - if self.requires_inline(tcx) { - return true; - } - if let ty::InstanceKind::DropGlue(.., Some(ty)) - | ty::InstanceKind::AsyncDropGlueCtorShim(.., Some(ty)) = *self - { - // Drop glue generally wants to be instantiated at every codegen - // unit, but without an #[inline] hint. We should make this - // available to normal end-users. - if tcx.sess.opts.incremental.is_none() { - return true; - } - // When compiling with incremental, we can generate a *lot* of - // codegen units. Including drop glue into all of them has a - // considerable compile time cost. - // - // We include enums without destructors to allow, say, optimizing - // drops of `Option::None` before LTO. We also respect the intent of - // `#[inline]` on `Drop::drop` implementations. - return ty.ty_adt_def().map_or(true, |adt_def| { - match *self { - ty::InstanceKind::DropGlue(..) => adt_def.destructor(tcx).map(|dtor| dtor.did), - ty::InstanceKind::AsyncDropGlueCtorShim(..) => { - adt_def.async_destructor(tcx).map(|dtor| dtor.ctor) - } - _ => unreachable!(), - } - .map_or_else(|| adt_def.is_enum(), |did| tcx.cross_crate_inlinable(did)) - }); - } - if let ty::InstanceKind::ThreadLocalShim(..) = *self { - return false; - } tcx.cross_crate_inlinable(self.def_id()) } diff --git a/compiler/rustc_mir_transform/src/cross_crate_inline.rs b/compiler/rustc_mir_transform/src/cross_crate_inline.rs index 483fd753e7077..4870be22ce2ad 100644 --- a/compiler/rustc_mir_transform/src/cross_crate_inline.rs +++ b/compiler/rustc_mir_transform/src/cross_crate_inline.rs @@ -3,6 +3,7 @@ use crate::pass_manager as pm; use rustc_attr::InlineAttr; use rustc_hir::def::DefKind; use rustc_hir::def_id::LocalDefId; +use rustc_hir::LangItem; use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use rustc_middle::query::Providers; @@ -16,6 +17,21 @@ pub fn provide(providers: &mut Providers) { } fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { + // Bail quickly for DefIds that wouldn't be inlinable anyway, such as statics. + if !matches!( + tcx.def_kind(def_id), + DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Ctor(..) + ) { + return false; + } + + // The program entrypoint is never inlinable in any sense. + if let Some((entry_fn, _)) = tcx.entry_fn(()) { + if def_id == entry_fn.expect_local() { + return false; + } + } + let codegen_fn_attrs = tcx.codegen_fn_attrs(def_id); // If this has an extern indicator, then this function is globally shared and thus will not // generate cgu-internal copies which would make it cross-crate inlinable. @@ -23,17 +39,12 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { return false; } - // This just reproduces the logic from Instance::requires_inline. - match tcx.def_kind(def_id) { - DefKind::Ctor(..) | DefKind::Closure => return true, - DefKind::Fn | DefKind::AssocFn => {} - _ => return false, - } - - // From this point on, it is valid to return true or false. - if tcx.sess.opts.unstable_opts.cross_crate_inline_threshold == InliningThreshold::Always { - return true; - } + // From this point on, it is technically valid to return true or false. + let threshold = match tcx.sess.opts.unstable_opts.cross_crate_inline_threshold { + InliningThreshold::Always => return true, + InliningThreshold::Sometimes(threshold) => threshold, + InliningThreshold::Never => return false, + }; if tcx.has_attr(def_id, sym::rustc_intrinsic) { // Intrinsic fallback bodies are always cross-crate inlineable. @@ -43,18 +54,18 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { return true; } + // Don't do any inference when incremental compilation is enabled; the additional inlining that + // inference permits also creates more work for small edits. + if tcx.sess.opts.incremental.is_some() { + return false; + } + // Obey source annotations first; this is important because it means we can use // #[inline(never)] to force code generation. match codegen_fn_attrs.inline { InlineAttr::Never => return false, InlineAttr::Hint | InlineAttr::Always => return true, - _ => {} - } - - // Don't do any inference when incremental compilation is enabled; the additional inlining that - // inference permits also creates more work for small edits. - if tcx.sess.opts.incremental.is_some() { - return false; + InlineAttr::None => {} } // Don't do any inference if codegen optimizations are disabled and also MIR inlining is not @@ -62,23 +73,36 @@ fn cross_crate_inlinable(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { // which is less confusing than having to also enable -Copt-level=1. if matches!(tcx.sess.opts.optimize, OptLevel::No) && !pm::should_run_pass(tcx, &inline::Inline) { - return false; + if !matches!(tcx.def_kind(def_id), DefKind::Ctor(..)) { + return false; + } } - if !tcx.is_mir_available(def_id) { - return false; + if tcx.is_lang_item(def_id.into(), LangItem::DropInPlace) + || tcx.is_lang_item(def_id.into(), LangItem::AsyncDropInPlace) + { + return true; } - let threshold = match tcx.sess.opts.unstable_opts.cross_crate_inline_threshold { - InliningThreshold::Always => return true, - InliningThreshold::Sometimes(threshold) => threshold, - InliningThreshold::Never => return false, - }; + // If there is no MIR for the DefId, we can't analyze the body. But also, this only arises in + // two relevant cases: extern functions and MIR shims. So here we recognize the MIR shims by a + // DefId that has no MIR and whose parent is one of the shimmed traits. + // Everything else is extern functions, and thus not a candidate for inlining. + if !tcx.is_mir_available(def_id) { + let parent = tcx.parent(def_id.into()); + match tcx.lang_items().from_def_id(parent.into()) { + Some(LangItem::Clone | LangItem::FnOnce | LangItem::Fn | LangItem::FnMut) => { + return true; + } + _ => return false, + } + } let mir = tcx.optimized_mir(def_id); let mut checker = CostChecker { tcx, callee_body: mir, calls: 0, statements: 0, landing_pads: 0, resumes: 0 }; checker.visit_body(mir); + checker.calls == 0 && checker.resumes == 0 && checker.landing_pads == 0 diff --git a/compiler/rustc_monomorphize/src/partitioning.rs b/compiler/rustc_monomorphize/src/partitioning.rs index 8c7c5e0074abf..8e3f0ab47c75b 100644 --- a/compiler/rustc_monomorphize/src/partitioning.rs +++ b/compiler/rustc_monomorphize/src/partitioning.rs @@ -98,7 +98,11 @@ use std::fs::{self, File}; use std::io::{BufWriter, Write}; use std::path::{Path, PathBuf}; +use rustc_data_structures::base_n::ToBaseN; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; +use rustc_data_structures::stable_hasher::Hash64; +use rustc_data_structures::stable_hasher::HashStable; +use rustc_data_structures::stable_hasher::StableHasher; use rustc_data_structures::sync; use rustc_data_structures::unord::{UnordMap, UnordSet}; use rustc_hir::def::DefKind; @@ -195,10 +199,73 @@ where codegen_units } +fn place_mono_items_incr<'tcx, I>( + cx: &PartitioningCx<'_, 'tcx>, + mono_items: I, +) -> PlacedMonoItems<'tcx> +where + I: Iterator>, +{ + let mut codegen_units = UnordMap::default(); + + let mut reachable_inlined_items = FxIndexSet::default(); + + for mono_item in mono_items { + // Instantiate everything as GloballyShared in its own CGU + let symbol_name = mono_item.symbol_name(cx.tcx).name; + + let hash = cx.tcx.with_stable_hashing_context(|mut hcx| { + let mut hasher = StableHasher::new(); + symbol_name.hash_stable(&mut hcx, &mut hasher); + hasher.finish::().as_u64() + }); + + let cgu_name = Symbol::intern(&hash.to_base(62)); + + let cgu = codegen_units.entry(cgu_name).or_insert_with(|| CodegenUnit::new(cgu_name)); + + let linkage = Linkage::External; + let visibility = Visibility::Default; + + let size_estimate = mono_item.size_estimate(cx.tcx); + + cgu.items_mut() + .insert(mono_item, MonoItemData { inlined: false, linkage, visibility, size_estimate }); + + get_reachable_inlined_items(cx.tcx, mono_item, cx.usage_map, &mut reachable_inlined_items); + } + + let symbol = Symbol::intern("upstream"); + let cgu = codegen_units.entry(symbol).or_insert_with(|| CodegenUnit::new(symbol)); + + for inlined_item in reachable_inlined_items { + cgu.items_mut().entry(inlined_item).or_insert_with(|| MonoItemData { + inlined: false, + linkage: Linkage::External, + visibility: Visibility::Default, + size_estimate: inlined_item.size_estimate(cx.tcx), + }); + } + + let mut codegen_units: Vec<_> = cx.tcx.with_stable_hashing_context(|ref hcx| { + codegen_units.into_items().map(|(_, cgu)| cgu).collect_sorted(hcx, true) + }); + + for cgu in codegen_units.iter_mut() { + cgu.compute_size_estimate(); + } + + return PlacedMonoItems { codegen_units, internalization_candidates: UnordSet::default() }; +} + fn place_mono_items<'tcx, I>(cx: &PartitioningCx<'_, 'tcx>, mono_items: I) -> PlacedMonoItems<'tcx> where I: Iterator>, { + if cx.tcx.sess.opts.incremental.is_some() { + return place_mono_items_incr(cx, mono_items); + } + let mut codegen_units = UnordMap::default(); let is_incremental_build = cx.tcx.sess.opts.incremental.is_some(); let mut internalization_candidates = UnordSet::default(); @@ -295,20 +362,20 @@ where } return PlacedMonoItems { codegen_units, internalization_candidates }; +} - fn get_reachable_inlined_items<'tcx>( - tcx: TyCtxt<'tcx>, - item: MonoItem<'tcx>, - usage_map: &UsageMap<'tcx>, - visited: &mut FxIndexSet>, - ) { - usage_map.for_each_inlined_used_item(tcx, item, |inlined_item| { - let is_new = visited.insert(inlined_item); - if is_new { - get_reachable_inlined_items(tcx, inlined_item, usage_map, visited); - } - }); - } +fn get_reachable_inlined_items<'tcx>( + tcx: TyCtxt<'tcx>, + item: MonoItem<'tcx>, + usage_map: &UsageMap<'tcx>, + visited: &mut FxIndexSet>, +) { + usage_map.for_each_inlined_used_item(tcx, item, |inlined_item| { + let is_new = visited.insert(inlined_item); + if is_new { + get_reachable_inlined_items(tcx, inlined_item, usage_map, visited); + } + }); } // This function requires the CGUs to be sorted by name on input, and ensures @@ -322,6 +389,10 @@ fn merge_codegen_units<'tcx>( // A sorted order here ensures merging is deterministic. assert!(codegen_units.is_sorted_by(|a, b| a.name().as_str() <= b.name().as_str())); + if cx.tcx.sess.opts.incremental.is_some() { + return; + } + // This map keeps track of what got merged into what. let mut cgu_contents: UnordMap> = codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name()])).collect(); diff --git a/tests/codegen/closures-without-inlinehint.rs b/tests/codegen/closures-without-inlinehint.rs new file mode 100644 index 0000000000000..9182de5a354a0 --- /dev/null +++ b/tests/codegen/closures-without-inlinehint.rs @@ -0,0 +1,21 @@ +//@ incremental +//@ compile-flags: -Cno-prepopulate-passes -Csymbol-mangling-version=v0 -Zinline-mir=no -Copt-level=0 + +#![crate_type = "lib"] + +pub fn f() { + let c = || { + let mut a = [0, 1, 2, 3, 4, 5, 6]; + a[0] = 0; + a[1] = 0; + a[2] = 0; + a[3] = 0; + a[4] = 0; + a[5] = 0; + a + }; + c(); +} + +// CHECK: ; closures_without_inlinehint::f::{closure#0} +// CHECK-NOT: ; Function Attrs: inlinehint diff --git a/tests/coverage/closure.cov-map b/tests/coverage/closure.cov-map index 6edd35921fe95..f36ef7af7ac38 100644 --- a/tests/coverage/closure.cov-map +++ b/tests/coverage/closure.cov-map @@ -31,18 +31,16 @@ Number of file 0 mappings: 24 = (c0 - c1) - Code(Counter(0)) at (prev + 1, 5) to (start + 3, 2) -Function name: closure::main::{closure#0} -Raw bytes (26): 0x[01, 01, 01, 01, 05, 04, 01, 28, 05, 02, 14, 05, 02, 15, 02, 0a, 02, 02, 0a, 00, 0b, 01, 01, 09, 01, 06] +Function name: closure::main::{closure#0} (unused) +Raw bytes (24): 0x[01, 01, 00, 04, 00, 28, 05, 02, 14, 00, 02, 15, 02, 0a, 00, 02, 0a, 00, 0b, 00, 01, 09, 01, 06] Number of files: 1 - file 0 => global file 1 -Number of expressions: 1 -- expression 0 operands: lhs = Counter(0), rhs = Counter(1) +Number of expressions: 0 Number of file 0 mappings: 4 -- Code(Counter(0)) at (prev + 40, 5) to (start + 2, 20) -- Code(Counter(1)) at (prev + 2, 21) to (start + 2, 10) -- Code(Expression(0, Sub)) at (prev + 2, 10) to (start + 0, 11) - = (c0 - c1) -- Code(Counter(0)) at (prev + 1, 9) to (start + 1, 6) +- Code(Zero) at (prev + 40, 5) to (start + 2, 20) +- Code(Zero) at (prev + 2, 21) to (start + 2, 10) +- Code(Zero) at (prev + 2, 10) to (start + 0, 11) +- Code(Zero) at (prev + 1, 9) to (start + 1, 6) Function name: closure::main::{closure#10} (unused) Raw bytes (10): 0x[01, 01, 00, 01, 00, 9b, 01, 07, 00, 21] diff --git a/tests/rustdoc/intra-doc/auxiliary/my-core.rs b/tests/rustdoc/intra-doc/auxiliary/my-core.rs index c050929db9682..0d75ae3628131 100644 --- a/tests/rustdoc/intra-doc/auxiliary/my-core.rs +++ b/tests/rustdoc/intra-doc/auxiliary/my-core.rs @@ -1,4 +1,4 @@ -#![feature(no_core, lang_items, rustdoc_internals, rustc_attrs)] +#![feature(no_core, lang_items, rustdoc_internals, rustc_attrs, arbitrary_self_types)] #![no_core] #![rustc_coherence_is_core] #![crate_type="rlib"] @@ -16,8 +16,13 @@ impl char { #[lang = "sized"] pub trait Sized {} +#[lang = "receiver"] +pub trait Receiver {} + #[lang = "clone"] -pub trait Clone: Sized {} +pub trait Clone: Sized { + fn clone(&self) -> Self; +} #[lang = "copy"] pub trait Copy: Clone {}