diff --git a/src/libcore/fmt/builders.rs b/src/libcore/fmt/builders.rs index e6e3454b36f81..dcdd26634de46 100644 --- a/src/libcore/fmt/builders.rs +++ b/src/libcore/fmt/builders.rs @@ -165,6 +165,62 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { self } + /// Marks the struct as non-exhaustive, indicating to the reader that there are some other + /// fields that are not shown in the debug representation. + /// + /// # Examples + /// + /// ``` + /// # #![feature(debug_non_exhaustive)] + /// use std::fmt; + /// + /// struct Bar { + /// bar: i32, + /// hidden: f32, + /// } + /// + /// impl fmt::Debug for Bar { + /// fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + /// fmt.debug_struct("Bar") + /// .field("bar", &self.bar) + /// .finish_non_exhaustive() // Show that some other field(s) exist. + /// } + /// } + /// + /// assert_eq!( + /// format!("{:?}", Bar { bar: 10, hidden: 1.0 }), + /// "Bar { bar: 10, .. }", + /// ); + /// ``` + #[unstable(feature = "debug_non_exhaustive", issue = "67364")] + pub fn finish_non_exhaustive(&mut self) -> fmt::Result { + self.result = self.result.and_then(|_| { + // Draw non-exhaustive dots (`..`), and open brace if necessary (no fields). + if self.is_pretty() { + if !self.has_fields { + self.fmt.write_str(" {\n")?; + } + let mut slot = None; + let mut state = Default::default(); + let mut writer = PadAdapter::wrap(&mut self.fmt, &mut slot, &mut state); + writer.write_str("..\n")?; + } else { + if self.has_fields { + self.fmt.write_str(", ..")?; + } else { + self.fmt.write_str(" { ..")?; + } + } + if self.is_pretty() { + self.fmt.write_str("}")? + } else { + self.fmt.write_str(" }")?; + } + Ok(()) + }); + self.result + } + /// Finishes output and returns any error encountered. /// /// # Examples @@ -194,15 +250,16 @@ impl<'a, 'b: 'a> DebugStruct<'a, 'b> { /// ``` #[stable(feature = "debug_builders", since = "1.2.0")] pub fn finish(&mut self) -> fmt::Result { - if self.has_fields { - self.result = self.result.and_then(|_| { + self.result = self.result.and_then(|_| { + if self.has_fields { if self.is_pretty() { - self.fmt.write_str("}") + self.fmt.write_str("}")? } else { - self.fmt.write_str(" }") + self.fmt.write_str(" }")?; } - }); - } + } + Ok(()) + }); self.result } diff --git a/src/libcore/tests/fmt/builders.rs b/src/libcore/tests/fmt/builders.rs index 255724432816d..8f426abe43ffa 100644 --- a/src/libcore/tests/fmt/builders.rs +++ b/src/libcore/tests/fmt/builders.rs @@ -93,6 +93,89 @@ mod debug_struct { }", format!("{:#?}", Bar)); } + + #[test] + fn test_only_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("Foo") + .finish_non_exhaustive() + } + } + + + assert_eq!("Foo { .. }", format!("{:?}", Foo)); + assert_eq!( +"Foo { + .. +}", + format!("{:#?}", Foo)); + } + + #[test] + fn test_multiple_and_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("Foo") + .field("bar", &true) + .field("baz", &format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + assert_eq!("Foo { bar: true, baz: 10/20, .. }", format!("{:?}", Foo)); + assert_eq!( +"Foo { + bar: true, + baz: 10/20, + .. +}", + format!("{:#?}", Foo)); + } + + #[test] + fn test_nested_non_exhaustive() { + struct Foo; + + impl fmt::Debug for Foo { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("Foo") + .field("bar", &true) + .field("baz", &format_args!("{}/{}", 10, 20)) + .finish_non_exhaustive() + } + } + + struct Bar; + + impl fmt::Debug for Bar { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt.debug_struct("Bar") + .field("foo", &Foo) + .field("hello", &"world") + .finish_non_exhaustive() + } + } + + assert_eq!("Bar { foo: Foo { bar: true, baz: 10/20, .. }, hello: \"world\", .. }", + format!("{:?}", Bar)); + assert_eq!( +"Bar { + foo: Foo { + bar: true, + baz: 10/20, + .. + }, + hello: \"world\", + .. +}", + format!("{:#?}", Bar)); + } + } mod debug_tuple { diff --git a/src/libcore/tests/lib.rs b/src/libcore/tests/lib.rs index b28ed2eaa0876..904c37fe54255 100644 --- a/src/libcore/tests/lib.rs +++ b/src/libcore/tests/lib.rs @@ -5,6 +5,7 @@ #![feature(core_private_bignum)] #![feature(core_private_diy_float)] #![feature(debug_map_key_value)] +#![feature(debug_non_exhaustive)] #![feature(dec2flt)] #![feature(exact_size_is_empty)] #![feature(fixed_size_array)] diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs index 78a31f4e54466..15bbfa7860fa7 100644 --- a/src/librustc/ty/mod.rs +++ b/src/librustc/ty/mod.rs @@ -212,6 +212,17 @@ pub enum AssocKind { Type } +impl AssocKind { + pub fn suggestion_descr(&self) -> &'static str { + match self { + ty::AssocKind::Method => "method call", + ty::AssocKind::Type | + ty::AssocKind::OpaqueTy => "associated type", + ty::AssocKind::Const => "associated constant", + } + } +} + impl AssocItem { pub fn def_kind(&self) -> DefKind { match self.kind { diff --git a/src/librustc_codegen_llvm/back/lto.rs b/src/librustc_codegen_llvm/back/lto.rs index 0e4e4e2f983f6..6481ef5c73ce0 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/src/librustc_codegen_llvm/back/lto.rs @@ -16,15 +16,24 @@ use rustc::hir::def_id::LOCAL_CRATE; use rustc::middle::exported_symbols::SymbolExportLevel; use rustc::session::config::{self, Lto}; use rustc::util::common::time_ext; -use rustc_data_structures::fx::FxHashMap; +use rustc_data_structures::fx::{FxHashSet, FxHashMap}; use rustc_codegen_ssa::{RLIB_BYTECODE_EXTENSION, ModuleCodegen, ModuleKind}; use log::{info, debug}; use std::ffi::{CStr, CString}; +use std::fs::File; +use std::io; +use std::mem; +use std::path::Path; use std::ptr; use std::slice; use std::sync::Arc; +/// We keep track of past LTO imports that were used to produce the current set +/// of compiled object files that we might choose to reuse during this +/// compilation session. +pub const THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME: &str = "thin-lto-past-imports.bin"; + pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool { match crate_type { config::CrateType::Executable | @@ -472,13 +481,26 @@ fn thin_lto(cgcx: &CodegenContext, info!("thin LTO data created"); - let import_map = if cgcx.incr_comp_session_dir.is_some() { - ThinLTOImports::from_thin_lto_data(data) + let (import_map_path, prev_import_map, curr_import_map) = + if let Some(ref incr_comp_session_dir) = cgcx.incr_comp_session_dir + { + let path = incr_comp_session_dir.join(THIN_LTO_IMPORTS_INCR_COMP_FILE_NAME); + // If previous imports have been deleted, or we get an IO error + // reading the file storing them, then we'll just use `None` as the + // prev_import_map, which will force the code to be recompiled. + let prev = if path.exists() { + ThinLTOImports::load_from_file(&path).ok() + } else { + None + }; + let curr = ThinLTOImports::from_thin_lto_data(data); + (Some(path), prev, curr) } else { // If we don't compile incrementally, we don't need to load the // import data from LLVM. assert!(green_modules.is_empty()); - ThinLTOImports::default() + let curr = ThinLTOImports::default(); + (None, None, curr) }; info!("thin LTO import map loaded"); @@ -502,18 +524,36 @@ fn thin_lto(cgcx: &CodegenContext, for (module_index, module_name) in shared.module_names.iter().enumerate() { let module_name = module_name_to_str(module_name); - // If the module hasn't changed and none of the modules it imports - // from has changed, we can re-use the post-ThinLTO version of the - // module. - if green_modules.contains_key(module_name) { - let imports_all_green = import_map.modules_imported_by(module_name) + // If (1.) the module hasn't changed, and (2.) none of the modules + // it imports from has changed, *and* (3.) the import-set itself has + // not changed from the previous compile when it was last + // ThinLTO'ed, then we can re-use the post-ThinLTO version of the + // module. Otherwise, freshly perform LTO optimization. + // + // This strategy means we can always save the computed imports as + // canon: when we reuse the post-ThinLTO version, condition (3.) + // ensures that the curent import set is the same as the previous + // one. (And of course, when we don't reuse the post-ThinLTO + // version, the current import set *is* the correct one, since we + // are doing the ThinLTO in this current compilation cycle.) + // + // See rust-lang/rust#59535. + if let (Some(prev_import_map), true) = + (prev_import_map.as_ref(), green_modules.contains_key(module_name)) + { + assert!(cgcx.incr_comp_session_dir.is_some()); + + let prev_imports = prev_import_map.modules_imported_by(module_name); + let curr_imports = curr_import_map.modules_imported_by(module_name); + let imports_all_green = curr_imports .iter() .all(|imported_module| green_modules.contains_key(imported_module)); - if imports_all_green { + if imports_all_green && equivalent_as_sets(prev_imports, curr_imports) { let work_product = green_modules[module_name].clone(); copy_jobs.push(work_product); info!(" - {}: re-used", module_name); + assert!(cgcx.incr_comp_session_dir.is_some()); cgcx.cgu_reuse_tracker.set_actual_reuse(module_name, CguReuse::PostLto); continue @@ -527,10 +567,33 @@ fn thin_lto(cgcx: &CodegenContext, })); } + // Save the curent ThinLTO import information for the next compilation + // session, overwriting the previous serialized imports (if any). + if let Some(path) = import_map_path { + if let Err(err) = curr_import_map.save_to_file(&path) { + let msg = format!("Error while writing ThinLTO import data: {}", err); + return Err(write::llvm_err(&diag_handler, &msg)); + } + } + Ok((opt_jobs, copy_jobs)) } } +/// Given two slices, each with no repeat elements. returns true if and only if +/// the two slices have the same contents when considered as sets (i.e. when +/// element order is disregarded). +fn equivalent_as_sets(a: &[String], b: &[String]) -> bool { + // cheap path: unequal lengths means cannot possibly be set equivalent. + if a.len() != b.len() { return false; } + // fast path: before building new things, check if inputs are equivalent as is. + if a == b { return true; } + // slow path: general set comparison. + let a: FxHashSet<&str> = a.iter().map(|s| s.as_str()).collect(); + let b: FxHashSet<&str> = b.iter().map(|s| s.as_str()).collect(); + a == b +} + pub(crate) fn run_pass_manager(cgcx: &CodegenContext, module: &ModuleCodegen, config: &ModuleConfig, @@ -832,6 +895,47 @@ impl ThinLTOImports { self.imports.get(llvm_module_name).map(|v| &v[..]).unwrap_or(&[]) } + fn save_to_file(&self, path: &Path) -> io::Result<()> { + use std::io::Write; + let file = File::create(path)?; + let mut writer = io::BufWriter::new(file); + for (importing_module_name, imported_modules) in &self.imports { + writeln!(writer, "{}", importing_module_name)?; + for imported_module in imported_modules { + writeln!(writer, " {}", imported_module)?; + } + writeln!(writer)?; + } + Ok(()) + } + + fn load_from_file(path: &Path) -> io::Result { + use std::io::BufRead; + let mut imports = FxHashMap::default(); + let mut current_module = None; + let mut current_imports = vec![]; + let file = File::open(path)?; + for line in io::BufReader::new(file).lines() { + let line = line?; + if line.is_empty() { + let importing_module = current_module + .take() + .expect("Importing module not set"); + imports.insert(importing_module, + mem::replace(&mut current_imports, vec![])); + } else if line.starts_with(" ") { + // Space marks an imported module + assert_ne!(current_module, None); + current_imports.push(line.trim().to_string()); + } else { + // Otherwise, beginning of a new module (must be start or follow empty line) + assert_eq!(current_module, None); + current_module = Some(line.trim().to_string()); + } + } + Ok(ThinLTOImports { imports }) + } + /// Loads the ThinLTO import map from ThinLTOData. unsafe fn from_thin_lto_data(data: *const llvm::ThinLTOData) -> ThinLTOImports { unsafe extern "C" fn imported_module_callback(payload: *mut libc::c_void, diff --git a/src/librustc_typeck/check/expr.rs b/src/librustc_typeck/check/expr.rs index fc7d19766373a..19441be87b959 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/src/librustc_typeck/check/expr.rs @@ -1425,8 +1425,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field: ast::Ident, ) -> Ty<'tcx> { let expr_t = self.check_expr_with_needs(base, needs); - let expr_t = self.structurally_resolved_type(base.span, - expr_t); + let expr_t = self.structurally_resolved_type(base.span, expr_t); let mut private_candidate = None; let mut autoderef = self.autoderef(expr.span, expr_t); while let Some((base_t, _)) = autoderef.next() { diff --git a/src/librustc_typeck/check/method/suggest.rs b/src/librustc_typeck/check/method/suggest.rs index f4b53b4d10604..9cd8c9abfd783 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/src/librustc_typeck/check/method/suggest.rs @@ -15,7 +15,7 @@ use rustc::traits::Obligation; use rustc::ty::{self, Ty, TyCtxt, ToPolyTraitRef, ToPredicate, TypeFoldable}; use rustc::ty::print::with_crate_prefix; use syntax_pos::{Span, FileName}; -use syntax::ast; +use syntax::{ast, source_map}; use syntax::util::lev_distance; use rustc_error_codes::*; @@ -79,37 +79,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; } - let print_disambiguation_help = | - err: &mut DiagnosticBuilder<'_>, - trait_name: String, - | { - err.help(&format!( - "to disambiguate the method call, write `{}::{}({}{})` instead", - trait_name, - item_name, - if rcvr_ty.is_region_ptr() && args.is_some() { - if rcvr_ty.is_mutable_ptr() { - "&mut " - } else { - "&" - } - } else { - "" - }, - args.map(|arg| arg - .iter() - .map(|arg| self.tcx.sess.source_map().span_to_snippet(arg.span) - .unwrap_or_else(|_| "...".to_owned())) - .collect::>() - .join(", ") - ).unwrap_or_else(|| "...".to_owned()) - )); - }; - let report_candidates = | span: Span, err: &mut DiagnosticBuilder<'_>, mut sources: Vec, + sugg_span: Span, | { sources.sort(); sources.dedup(); @@ -150,15 +124,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - let note_str = if sources.len() > 1 { - format!("candidate #{} is defined in an impl{} for the type `{}`", - idx + 1, - insertion, - impl_ty) + let (note_str, idx) = if sources.len() > 1 { + (format!( + "candidate #{} is defined in an impl{} for the type `{}`", + idx + 1, + insertion, + impl_ty, + ), Some(idx + 1)) } else { - format!("the candidate is defined in an impl{} for the type `{}`", - insertion, - impl_ty) + (format!( + "the candidate is defined in an impl{} for the type `{}`", + insertion, + impl_ty, + ), None) }; if let Some(note_span) = note_span { // We have a span pointing to the method. Show note with snippet. @@ -168,7 +146,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.note(¬e_str); } if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) { - print_disambiguation_help(err, self.tcx.def_path_str(trait_ref.def_id)); + let path = self.tcx.def_path_str(trait_ref.def_id); + + let ty = match item.kind { + ty::AssocKind::Const | + ty::AssocKind::Type | + ty::AssocKind::OpaqueTy => rcvr_ty, + ty::AssocKind::Method => self.tcx.fn_sig(item.def_id) + .inputs() + .skip_binder() + .get(0) + .filter(|ty| ty.is_region_ptr() && !rcvr_ty.is_region_ptr()) + .map(|ty| *ty) + .unwrap_or(rcvr_ty), + }; + print_disambiguation_help( + item_name, + args, + err, + path, + ty, + item.kind, + sugg_span, + idx, + self.tcx.sess.source_map(), + ); } } CandidateSource::TraitSource(trait_did) => { @@ -182,19 +184,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let item_span = self.tcx.sess.source_map() .def_span(self.tcx.def_span(item.def_id)); - if sources.len() > 1 { + let idx = if sources.len() > 1 { span_note!(err, item_span, "candidate #{} is defined in the trait `{}`", idx + 1, self.tcx.def_path_str(trait_did)); + Some(idx + 1) } else { span_note!(err, item_span, "the candidate is defined in the trait `{}`", self.tcx.def_path_str(trait_did)); - } - print_disambiguation_help(err, self.tcx.def_path_str(trait_did)); + None + }; + let path = self.tcx.def_path_str(trait_did); + print_disambiguation_help( + item_name, + args, + err, + path, + rcvr_ty, + item.kind, + sugg_span, + idx, + self.tcx.sess.source_map(), + ); } } } @@ -203,6 +218,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; + let sugg_span = if let SelfSource::MethodCall(expr) = source { + // Given `foo.bar(baz)`, `expr` is `bar`, but we want to point to the whole thing. + self.tcx.hir().expect_expr(self.tcx.hir().get_parent_node(expr.hir_id)).span + } else { + span + }; + match error { MethodError::NoMatch(NoMatchData { static_candidates: static_sources, @@ -495,9 +517,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } - report_candidates(span, &mut err, static_sources); + report_candidates(span, &mut err, static_sources, sugg_span); } else if static_sources.len() > 1 { - report_candidates(span, &mut err, static_sources); + report_candidates(span, &mut err, static_sources, sugg_span); } if !unsatisfied_predicates.is_empty() { @@ -584,7 +606,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "multiple applicable items in scope"); err.span_label(span, format!("multiple `{}` found", item_name)); - report_candidates(span, &mut err, sources); + report_candidates(span, &mut err, sources, sugg_span); err.emit(); } @@ -1123,3 +1145,56 @@ impl hir::intravisit::Visitor<'tcx> for UsePlacementFinder<'tcx> { hir::intravisit::NestedVisitorMap::None } } + +fn print_disambiguation_help( + item_name: ast::Ident, + args: Option<&'tcx [hir::Expr]>, + err: &mut DiagnosticBuilder<'_>, + trait_name: String, + rcvr_ty: Ty<'_>, + kind: ty::AssocKind, + span: Span, + candidate: Option, + source_map: &source_map::SourceMap, +) { + let mut applicability = Applicability::MachineApplicable; + let sugg_args = if let (ty::AssocKind::Method, Some(args)) = (kind, args) { + format!( + "({}{})", + if rcvr_ty.is_region_ptr() { + if rcvr_ty.is_mutable_ptr() { + "&mut " + } else { + "&" + } + } else { + "" + }, + args.iter() + .map(|arg| source_map.span_to_snippet(arg.span) + .unwrap_or_else(|_| { + applicability = Applicability::HasPlaceholders; + "_".to_owned() + })) + .collect::>() + .join(", "), + ) + } else { + String::new() + }; + let sugg = format!("{}::{}{}", trait_name, item_name, sugg_args); + err.span_suggestion( + span, + &format!( + "disambiguate the {} for {}", + kind.suggestion_descr(), + if let Some(candidate) = candidate { + format!("candidate #{}", candidate) + } else { + "the candidate".to_string() + }, + ), + sugg, + applicability, + ); +} diff --git a/src/test/incremental/thinlto/cgu_invalidated_when_import_added.rs b/src/test/incremental/thinlto/cgu_invalidated_when_import_added.rs new file mode 100644 index 0000000000000..42168dd273eff --- /dev/null +++ b/src/test/incremental/thinlto/cgu_invalidated_when_import_added.rs @@ -0,0 +1,62 @@ +// revisions: cfail1 cfail2 +// compile-flags: -O -Zhuman-readable-cgu-names -Cllvm-args=-import-instr-limit=10 +// build-pass + +// rust-lang/rust#59535: +// +// This is analgous to cgu_invalidated_when_import_removed.rs, but it covers +// the other direction: +// +// We start with a call-graph like `[A] -> [B -> D] [C]` (where the letters are +// functions and the modules are enclosed in `[]`), and add a new call `D <- C`, +// yielding the new call-graph: `[A] -> [B -> D] <- [C]` +// +// The effect of this is that the compiler previously classfied `D` as internal +// and the import-set of `[A]` to be just `B`. But after adding the `D <- C` call, +// `D` is no longer classified as internal, and the import-set of `[A]` becomes +// both `B` and `D`. +// +// We check this case because an early proposed pull request included an +// assertion that the import-sets monotonically decreased over time, a claim +// which this test case proves to be false. + +fn main() { + foo::foo(); + bar::baz(); +} + +mod foo { + + // In cfail1, ThinLTO decides that foo() does not get inlined into main, and + // instead bar() gets inlined into foo(). + // In cfail2, foo() gets inlined into main. + pub fn foo(){ + bar() + } + + // This function needs to be big so that it does not get inlined by ThinLTO + // but *does* get inlined into foo() when it is declared `internal` in + // cfail1 (alone). + pub fn bar(){ + println!("quux1"); + println!("quux2"); + println!("quux3"); + println!("quux4"); + println!("quux5"); + println!("quux6"); + println!("quux7"); + println!("quux8"); + println!("quux9"); + } +} + +mod bar { + + #[inline(never)] + pub fn baz() { + #[cfg(cfail2)] + { + crate::foo::bar(); + } + } +} diff --git a/src/test/incremental/thinlto/cgu_invalidated_when_import_removed.rs b/src/test/incremental/thinlto/cgu_invalidated_when_import_removed.rs new file mode 100644 index 0000000000000..19ce7b3e148f7 --- /dev/null +++ b/src/test/incremental/thinlto/cgu_invalidated_when_import_removed.rs @@ -0,0 +1,74 @@ +// revisions: cfail1 cfail2 +// compile-flags: -O -Zhuman-readable-cgu-names -Cllvm-args=-import-instr-limit=10 +// build-pass + +// rust-lang/rust#59535: +// +// Consider a call-graph like `[A] -> [B -> D] <- [C]` (where the letters are +// functions and the modules are enclosed in `[]`) +// +// In our specific instance, the earlier compilations were inlining the call +// to`B` into `A`; thus `A` ended up with a external reference to the symbol `D` +// in its object code, to be resolved at subsequent link time. The LTO import +// information provided by LLVM for those runs reflected that information: it +// explicitly says during those runs, `B` definition and `D` declaration were +// imported into `[A]`. +// +// The change between incremental builds was that the call `D <- C` was removed. +// +// That change, coupled with other decisions within `rustc`, made the compiler +// decide to make `D` an internal symbol (since it was no longer accessed from +// other codegen units, this makes sense locally). And then the definition of +// `D` was inlined into `B` and `D` itself was eliminated entirely. +// +// The current LTO import information reported that `B` alone is imported into +// `[A]` for the *current compilation*. So when the Rust compiler surveyed the +// dependence graph, it determined that nothing `[A]` imports changed since the +// last build (and `[A]` itself has not changed either), so it chooses to reuse +// the object code generated during the previous compilation. +// +// But that previous object code has an unresolved reference to `D`, and that +// causes a link time failure! + +fn main() { + foo::foo(); + bar::baz(); +} + +mod foo { + + // In cfail1, foo() gets inlined into main. + // In cfail2, ThinLTO decides that foo() does not get inlined into main, and + // instead bar() gets inlined into foo(). But faulty logic in our incr. + // ThinLTO implementation thought that `main()` is unchanged and thus reused + // the object file still containing a call to the now non-existant bar(). + pub fn foo(){ + bar() + } + + // This function needs to be big so that it does not get inlined by ThinLTO + // but *does* get inlined into foo() once it is declared `internal` in + // cfail2. + pub fn bar(){ + println!("quux1"); + println!("quux2"); + println!("quux3"); + println!("quux4"); + println!("quux5"); + println!("quux6"); + println!("quux7"); + println!("quux8"); + println!("quux9"); + } +} + +mod bar { + + #[inline(never)] + pub fn baz() { + #[cfg(cfail1)] + { + crate::foo::bar(); + } + } +} diff --git a/src/test/run-make/removing-code-and-incremental-lto/Makefile b/src/test/run-make/removing-code-and-incremental-lto/Makefile new file mode 100644 index 0000000000000..4d87781c4cb4e --- /dev/null +++ b/src/test/run-make/removing-code-and-incremental-lto/Makefile @@ -0,0 +1,87 @@ +-include ../../run-make-fulldeps/tools.mk + +# How to run this +# $ ./x.py clean +# $ ./x.py test --target thumbv7m-none-eabi src/test/run-make + +# The original target of interest was thumbv7em-none-eabi +# +# It is possible that other targets could be tested, but as long as we are +# testing *something*, that is enough for me. (Note that you should not just add +# `# only-target` lines; see rust-lang/rust#67018.) +ifeq (,$(filter $(TARGET),thumbv6m-none-eabi thumbv7em-none-eabi thumbv7em-none-eabihf thumbv7m-none-eabi)) + +all: + +else + +# This is a test of a scenario that arose in issue rust-lang/rust#59535. +# +# What the user experienced: deleting a method use caused a link-time failure. +# +# What the cause was: At the time, incremental compilation would determine which +# object files could be reused from a previous build based on, in part, 1. the +# "greenness" of the modules in the current crate (i.e. which modules' contents +# have changed since the incremental build) and 2. the current LTO import +# information of the modules in the current crate. +# +# The problem was that the reused object file could have been optimized based on +# LTO imports of a *previous* compile, not the current one. In other words, the +# past LTO import information could have included more modules than what the +# current LTO imports do, and those dependencies need to be respected when you +# decide what object files to reuse. +# +# To make this more concrete: Here is the the high-level description of the +# specific scenario from rust-lang/rust#59535: +# +# We had a call-graph like this: `[A] -> [B -> D] <- [C]`, where modules are in `[]` +# +# and the change between incremental builds was the `D <- C` link was removed. +# +# 1ST COMPILE: At the time of the first compile, LTO-optimization inlined the +# code from `B` into `A`, so that in the object code for `A`, there was now a +# direct link to the symbol for `D`. The LTO imports computed during this first +# compile showed this directly: it said that `[A]` imported `B` and `D`. +# +# 2ND COMPIILE: But on the second compile, after the developer removed the call +# `D <- C`, the Rust compiler itself determined that the `D` could be declared +# as an internal definition, and then LLVM optimized the definition of `D` away +# entirely. At the *same time*, the LTO imports computed during this second +# compile reported by LLVM said that `[A]` *solely* imported `B`, and so the +# Rust compiler's incremental reuse mechanism determined that we could reuse the +# object code previously generated (during the 1st compile) for `[A]`. This +# conclusion seemed valid to the compiler, because nothing changed about any +# imports that it knew of for `[A]` based on the current compile. + +### (Switch to rustup's nightly to observe bug) +# RUSTC := rustc +nightly +RUSTC := $(RUSTC_ORIGINAL) + +OUT_DIR = $(TMPDIR) + +INCREMENTAL_DIR = $(OUT_DIR)/incr +RUBBLE1_OUT_DIR = $(OUT_DIR)/rubble1 +RUBBLE2_OUT_DIR = $(OUT_DIR)/rubble2 + +LINK_X_DIR := . + +all: + mkdir -p $(OUT_DIR) + mkdir -p $(INCREMENTAL_DIR) + mkdir -p $(RUBBLE1_OUT_DIR) + mkdir -p $(RUBBLE2_OUT_DIR) + $(RUSTC) --crate-name cortex_m_rt cortex-m-rt.rs --crate-type lib --emit=metadata,link -C opt-level=s --out-dir $(OUT_DIR) --target $(TARGET) -C link-arg=-Tlink.x.in -L $(LINK_X_DIR) + $(RUSTC) --edition=2018 --crate-name nrf52810_hal nrf52810-hal.rs --crate-type lib --emit=metadata,link -C opt-level=s -C metadata=aa86958b67bf89f5 --out-dir $(OUT_DIR) --target $(TARGET) --extern cortex_m_rt=$(OUT_DIR)/libcortex_m_rt.rmeta -C link-arg=-Tlink.x.in -L $(LINK_X_DIR) + cp rubble.rs.v1 $(TMPDIR)/rubble.rs + $(RUSTC) --crate-name rubble $(TMPDIR)/rubble.rs --crate-type bin --emit=link -C opt-level=s --out-dir $(RUBBLE1_OUT_DIR) --target $(TARGET) -C incremental=$(INCREMENTAL_DIR) -L dependency=$(OUT_DIR) --extern nrf52810_hal=$(OUT_DIR)/libnrf52810_hal.rlib -C link-arg=-Tlink.x.in -L $(LINK_X_DIR) -C linker-flavor=ld.lld -C codegen-units=2 + cp rubble.rs.v2 $(TMPDIR)/rubble.rs + $(RUSTC) --crate-name rubble $(TMPDIR)/rubble.rs --crate-type bin --emit=link -C opt-level=s --out-dir $(RUBBLE2_OUT_DIR) --target $(TARGET) -C incremental=$(INCREMENTAL_DIR) -L dependency=$(OUT_DIR) --extern nrf52810_hal=$(OUT_DIR)/libnrf52810_hal.rlib -C link-arg=-Tlink.x.in -L $(LINK_X_DIR) -C linker-flavor=ld.lld -C codegen-units=2 + echo Now testing the reverse direction + rm -rf $(INCREMENTAL_DIR) + mkdir -p $(INCREMENTAL_DIR) + cp rubble.rs.v2 $(TMPDIR)/rubble.rs + $(RUSTC) --crate-name rubble $(TMPDIR)/rubble.rs --crate-type bin --emit=link -C opt-level=s --out-dir $(RUBBLE2_OUT_DIR) --target $(TARGET) -C incremental=$(INCREMENTAL_DIR) -L dependency=$(OUT_DIR) --extern nrf52810_hal=$(OUT_DIR)/libnrf52810_hal.rlib -C link-arg=-Tlink.x.in -L $(LINK_X_DIR) -C linker-flavor=ld.lld -C codegen-units=2 + cp rubble.rs.v1 $(TMPDIR)/rubble.rs + $(RUSTC) --crate-name rubble $(TMPDIR)/rubble.rs --crate-type bin --emit=link -C opt-level=s --out-dir $(RUBBLE1_OUT_DIR) --target $(TARGET) -C incremental=$(INCREMENTAL_DIR) -L dependency=$(OUT_DIR) --extern nrf52810_hal=$(OUT_DIR)/libnrf52810_hal.rlib -C link-arg=-Tlink.x.in -L $(LINK_X_DIR) -C linker-flavor=ld.lld -C codegen-units=2 + +endif diff --git a/src/test/run-make/removing-code-and-incremental-lto/cortex-m-rt.rs b/src/test/run-make/removing-code-and-incremental-lto/cortex-m-rt.rs new file mode 100644 index 0000000000000..1ecc41ea60ee8 --- /dev/null +++ b/src/test/run-make/removing-code-and-incremental-lto/cortex-m-rt.rs @@ -0,0 +1,13 @@ +#![no_std] + +#[link_section = ".vector_table.reset_vector"] +#[no_mangle] pub static __RESET_VECTOR: unsafe extern "C" fn() -> ! = Reset; + +extern "Rust" { fn main() -> !; } + +#[no_mangle] pub unsafe extern "C" fn Reset() -> ! { main() } + +#[no_mangle] pub unsafe extern "C" fn DefaultHandler_() -> ! { loop { } } + +#[link_section = ".vector_table.exceptions"] +#[no_mangle] pub static __EXCEPTIONS: [usize; 14] = [0; 14]; diff --git a/src/test/run-make/removing-code-and-incremental-lto/device.x b/src/test/run-make/removing-code-and-incremental-lto/device.x new file mode 100644 index 0000000000000..28f975e0790d2 --- /dev/null +++ b/src/test/run-make/removing-code-and-incremental-lto/device.x @@ -0,0 +1,3 @@ +/* Sample device.x file */ +PROVIDE(WWDG = DefaultHandler); +PROVIDE(PVD = DefaultHandler); diff --git a/src/test/run-make/removing-code-and-incremental-lto/link.x.in b/src/test/run-make/removing-code-and-incremental-lto/link.x.in new file mode 100644 index 0000000000000..30d4af101f231 --- /dev/null +++ b/src/test/run-make/removing-code-and-incremental-lto/link.x.in @@ -0,0 +1,213 @@ +/* # Developer notes + +- Symbols that start with a double underscore (__) are considered "private" + +- Symbols that start with a single underscore (_) are considered "semi-public"; they can be + overridden in a user linker script, but should not be referred from user code (e.g. `extern "C" { + static mut __sbss }`). + +- `EXTERN` forces the linker to keep a symbol in the final binary. We use this to make sure a + symbol if not dropped if it appears in or near the front of the linker arguments and "it's not + needed" by any of the preceding objects (linker arguments) + +- `PROVIDE` is used to provide default values that can be overridden by a user linker script + +- On alignment: it's important for correctness that the VMA boundaries of both .bss and .data *and* + the LMA of .data are all 4-byte aligned. These alignments are assumed by the RAM initialization + routine. There's also a second benefit: 4-byte aligned boundaries means that you won't see + "Address (..) is out of bounds" in the disassembly produced by `objdump`. +*/ + +/* Provides information about the memory layout of the device */ +/* This will be provided by the user (see `memory.x`) or by a Board Support Crate */ +INCLUDE memory.x + +/* # Entry point = reset vector */ +ENTRY(Reset); +EXTERN(__RESET_VECTOR); /* depends on the `Reset` symbol */ + +/* # Exception vectors */ +/* This is effectively weak aliasing at the linker level */ +/* The user can override any of these aliases by defining the corresponding symbol themselves (cf. + the `exception!` macro) */ +EXTERN(__EXCEPTIONS); /* depends on all the these PROVIDED symbols */ + +EXTERN(DefaultHandler); + +PROVIDE(NonMaskableInt = DefaultHandler); +EXTERN(HardFaultTrampoline); +PROVIDE(MemoryManagement = DefaultHandler); +PROVIDE(BusFault = DefaultHandler); +PROVIDE(UsageFault = DefaultHandler); +PROVIDE(SecureFault = DefaultHandler); +PROVIDE(SVCall = DefaultHandler); +PROVIDE(DebugMonitor = DefaultHandler); +PROVIDE(PendSV = DefaultHandler); +PROVIDE(SysTick = DefaultHandler); + +PROVIDE(DefaultHandler = DefaultHandler_); +PROVIDE(HardFault = HardFault_); + +/* # Interrupt vectors */ +EXTERN(__INTERRUPTS); /* `static` variable similar to `__EXCEPTIONS` */ + +/* # Pre-initialization function */ +/* If the user overrides this using the `pre_init!` macro or by creating a `__pre_init` function, + then the function this points to will be called before the RAM is initialized. */ +PROVIDE(__pre_init = DefaultPreInit); + +/* # Sections */ +SECTIONS +{ + PROVIDE(_stack_start = ORIGIN(RAM) + LENGTH(RAM)); + + /* ## Sections in FLASH */ + /* ### Vector table */ + .vector_table ORIGIN(FLASH) : + { + /* Initial Stack Pointer (SP) value */ + LONG(_stack_start); + + /* Reset vector */ + KEEP(*(.vector_table.reset_vector)); /* this is the `__RESET_VECTOR` symbol */ + __reset_vector = .; + + /* Exceptions */ + KEEP(*(.vector_table.exceptions)); /* this is the `__EXCEPTIONS` symbol */ + __eexceptions = .; + + /* Device specific interrupts */ + KEEP(*(.vector_table.interrupts)); /* this is the `__INTERRUPTS` symbol */ + } > FLASH + + PROVIDE(_stext = ADDR(.vector_table) + SIZEOF(.vector_table)); + + /* ### .text */ + .text _stext : + { + *(.text .text.*); + *(.HardFaultTrampoline); + *(.HardFault.*); + . = ALIGN(4); + __etext = .; + } > FLASH + + /* ### .rodata */ + .rodata __etext : ALIGN(4) + { + *(.rodata .rodata.*); + + /* 4-byte align the end (VMA) of this section. + This is required by LLD to ensure the LMA of the following .data + section will have the correct alignment. */ + . = ALIGN(4); + __erodata = .; + } > FLASH + + /* ## Sections in RAM */ + /* ### .data */ + .data : AT(__erodata) ALIGN(4) + { + . = ALIGN(4); + __sdata = .; + *(.data .data.*); + . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ + __edata = .; + } > RAM + + /* LMA of .data */ + __sidata = LOADADDR(.data); + + /* ### .bss */ + .bss : ALIGN(4) + { + . = ALIGN(4); + __sbss = .; + *(.bss .bss.*); + . = ALIGN(4); /* 4-byte align the end (VMA) of this section */ + __ebss = .; + } > RAM + + /* ### .uninit */ + .uninit (NOLOAD) : ALIGN(4) + { + . = ALIGN(4); + *(.uninit .uninit.*); + . = ALIGN(4); + } > RAM + + /* Place the heap right after `.uninit` */ + . = ALIGN(4); + __sheap = .; + + /* ## .got */ + /* Dynamic relocations are unsupported. This section is only used to detect relocatable code in + the input files and raise an error if relocatable code is found */ + .got (NOLOAD) : + { + KEEP(*(.got .got.*)); + } + + /* ## Discarded sections */ + /DISCARD/ : + { + /* Unused exception related info that only wastes space */ + *(.ARM.exidx); + *(.ARM.exidx.*); + *(.ARM.extab.*); + } +} + +/* Do not exceed this mark in the error messages below | */ +/* # Alignment checks */ +ASSERT(ORIGIN(FLASH) % 4 == 0, " +ERROR(cortex-m-rt): the start of the FLASH region must be 4-byte aligned"); + +ASSERT(ORIGIN(RAM) % 4 == 0, " +ERROR(cortex-m-rt): the start of the RAM region must be 4-byte aligned"); + +ASSERT(__sdata % 4 == 0 && __edata % 4 == 0, " +BUG(cortex-m-rt): .data is not 4-byte aligned"); + +ASSERT(__sidata % 4 == 0, " +BUG(cortex-m-rt): the LMA of .data is not 4-byte aligned"); + +ASSERT(__sbss % 4 == 0 && __ebss % 4 == 0, " +BUG(cortex-m-rt): .bss is not 4-byte aligned"); + +ASSERT(__sheap % 4 == 0, " +BUG(cortex-m-rt): start of .heap is not 4-byte aligned"); + +/* # Position checks */ + +/* ## .vector_table */ +ASSERT(__reset_vector == ADDR(.vector_table) + 0x8, " +BUG(cortex-m-rt): the reset vector is missing"); + +ASSERT(__eexceptions == ADDR(.vector_table) + 0x40, " +BUG(cortex-m-rt): the exception vectors are missing"); + +ASSERT(SIZEOF(.vector_table) > 0x40, " +ERROR(cortex-m-rt): The interrupt vectors are missing. +Possible solutions, from most likely to less likely: +- Link to a svd2rust generated device crate +- Disable the 'device' feature of cortex-m-rt to build a generic application (a dependency +may be enabling it) +- Supply the interrupt handlers yourself. Check the documentation for details."); + +/* ## .text */ +ASSERT(ADDR(.vector_table) + SIZEOF(.vector_table) <= _stext, " +ERROR(cortex-m-rt): The .text section can't be placed inside the .vector_table section +Set _stext to an address greater than the end of .vector_table (See output of `nm`)"); + +ASSERT(_stext + SIZEOF(.text) < ORIGIN(FLASH) + LENGTH(FLASH), " +ERROR(cortex-m-rt): The .text section must be placed inside the FLASH memory. +Set _stext to an address smaller than 'ORIGIN(FLASH) + LENGTH(FLASH)'"); + +/* # Other checks */ +ASSERT(SIZEOF(.got) == 0, " +ERROR(cortex-m-rt): .got section detected in the input object files +Dynamic relocations are not supported. If you are linking to C code compiled using +the 'cc' crate then modify your build script to compile the C code _without_ +the -fPIC flag. See the documentation of the `cc::Build.pic` method for details."); +/* Do not exceed this mark in the error messages above | */ diff --git a/src/test/run-make/removing-code-and-incremental-lto/memory.x b/src/test/run-make/removing-code-and-incremental-lto/memory.x new file mode 100644 index 0000000000000..1be105b582716 --- /dev/null +++ b/src/test/run-make/removing-code-and-incremental-lto/memory.x @@ -0,0 +1,23 @@ +/* Linker script for the nRF52 - WITHOUT SOFT DEVICE */ +MEMORY +{ + /* NOTE K = KiBi = 1024 bytes */ + FLASH : ORIGIN = 0x00000000, LENGTH = 192K + RAM : ORIGIN = 0x20000000, LENGTH = 24K +} + +/* This is where the call stack will be allocated. */ +/* The stack is of the full descending type. */ +/* You may want to use this variable to locate the call stack and static + variables in different memory regions. Below is shown the default value */ +/* _stack_start = ORIGIN(RAM) + LENGTH(RAM); */ + +/* You can use this symbol to customize the location of the .text section */ +/* If omitted the .text section will be placed right after the .vector_table + section */ +/* This is required only on microcontrollers that store some configuration right + after the vector table */ +/* _stext = ORIGIN(FLASH) + 0x400; */ + +/* Size of the heap (in bytes) */ +/* _heap_size = 1024; */ diff --git a/src/test/run-make/removing-code-and-incremental-lto/nrf52810-hal.rs b/src/test/run-make/removing-code-and-incremental-lto/nrf52810-hal.rs new file mode 100644 index 0000000000000..cae8f7192df21 --- /dev/null +++ b/src/test/run-make/removing-code-and-incremental-lto/nrf52810-hal.rs @@ -0,0 +1,1643 @@ +#![allow(non_camel_case_types, dead_code)] +#![no_std] + +pub mod nrf52810_pac { + extern crate cortex_m_rt; + pub struct Vector { _handler: unsafe extern "C" fn(), } + extern "C" fn power_clock_2() { } + + #[link_section = ".vector_table.interrupts"] + #[no_mangle] + pub static __INTERRUPTS: [Vector; 1] = [ Vector { _handler: power_clock_2 } ]; + + mod ficr { + mod info { + mod part { + #[derive(Debug, PartialEq)]struct PARTR; + struct R; + impl R { } + impl R { } + impl R { } + } + mod package { + #[derive(Debug, PartialEq)]struct PACKAGER; + struct R; + impl R { } + impl R { } + impl R { } + } + mod flash { + #[derive(Debug, PartialEq)]struct FLASHR; + struct R; + impl R { } + impl R { } + impl R { } + } + } + mod deviceaddrtype { + #[derive(Debug, PartialEq)]struct DEVICEADDRTYPER; + struct R; + impl R { } + impl R { } + impl R { } + } + } + mod bprot { + mod config0 { + #[derive(Debug, PartialEq)]struct REGION0R; + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION1R; + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION2R; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION3R; + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION4R; + impl R { } + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION5R; + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION6R; + impl R { } + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION7R; + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION8R; + impl R { } + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION9R; + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION10R; + impl R { } + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION11R; + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION12R; + impl R { } + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION13R; + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION14R; + impl R { } + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION15R; + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION16R; + impl R { } + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION17R; + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION18R; + impl R { } + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION19R; + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION20R; + impl R { } + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION21R; + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION22R; + impl R { } + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION23R; + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION24R; + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION25R; + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION26R; + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION27R; + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION28R; + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION29R; + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION30R; + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct REGION31R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod disableindebug { + struct R; + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct DISABLEINDEBUGR; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod twi0 { + mod psel { + mod scl { + struct R; + impl R { } + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct CONNECTR; + impl R { } + + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod sda { + struct R; + impl R { } + impl R { } + #[derive(Clone, Copy, Debug, PartialEq)]struct CONNECTR; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod events_stopped { + #[derive(Debug, PartialEq)]struct EVENTS_STOPPEDR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod events_txdsent { + #[derive(Debug, PartialEq)]struct EVENTS_TXDSENTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod events_bb { + #[derive(Debug, PartialEq)]struct EVENTS_BBR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod shorts { + #[derive(Debug, PartialEq)]struct BB_SUSPENDR; + #[derive(Debug, PartialEq)]struct BB_STOPR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod intenclr { + #[derive(Debug, PartialEq)]struct STOPPEDR; + #[derive(Debug, PartialEq)]struct RXDREADYR; + #[derive(Debug, PartialEq)]struct TXDSENTR; + #[derive(Debug, PartialEq)]struct ERRORR; + #[derive(Debug, PartialEq)]struct BBR; + #[derive(Debug, PartialEq)]struct SUSPENDEDR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod enable { + #[derive(Debug, PartialEq)]struct ENABLER; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod frequency { + #[derive(Debug, PartialEq)]struct FREQUENCYR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod twim0 { + mod psel { + mod scl { + #[derive(Debug, PartialEq)]struct CONNECTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod sda { + #[derive(Debug, PartialEq)]struct CONNECTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod txd { + mod ptr { + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod maxcnt { + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod amount { + struct R; + impl R { } + impl R { } + impl R { } + } + mod list { + #[derive(Debug, PartialEq)]struct LISTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod tasks_suspend { + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + } + mod events_error { + #[derive(Debug, PartialEq)]struct EVENTS_ERRORR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod events_rxstarted { + #[derive(Debug, PartialEq)]struct EVENTS_RXSTARTEDR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod events_lastrx { + #[derive(Debug, PartialEq)]struct EVENTS_LASTRXR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod shorts { + #[derive(Debug, PartialEq)]struct LASTTX_STARTRXR; + #[derive(Debug, PartialEq)]struct LASTTX_SUSPENDR; + #[derive(Debug, PartialEq)]struct LASTTX_STOPR; + #[derive(Debug, PartialEq)]struct LASTRX_STARTTXR; + #[derive(Clone, Copy, Debug, PartialEq)]struct LASTRX_SUSPENDR; + #[derive(Clone, Copy, Debug, PartialEq)]struct LASTRX_STOPR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod intenset { + #[derive(Clone, Copy, Debug, PartialEq)]struct STOPPEDR; + #[derive(Clone, Copy, Debug, PartialEq)]struct ERRORR; + #[derive(Clone, Copy, Debug, PartialEq)]struct SUSPENDEDR; + #[derive(Clone, Copy, Debug, PartialEq)]struct RXSTARTEDR; + #[derive(Clone, Copy, Debug, PartialEq)]struct TXSTARTEDR; + #[derive(Clone, Copy, Debug, PartialEq)]struct LASTRXR; + #[derive(Clone, Copy, Debug, PartialEq)]struct LASTTXR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod errorsrc { + #[derive(Clone, Copy, Debug, PartialEq)]struct OVERRUNR; + #[derive(Clone, Copy, Debug, PartialEq)]struct ANACKR; + #[derive(Clone, Copy, Debug, PartialEq)]struct DNACKR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod frequency { + #[derive(Clone, Copy, Debug, PartialEq)]struct FREQUENCYR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod twis0 { + mod psel { + mod scl { + #[derive(Clone, Copy, Debug, PartialEq)]struct CONNECTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod sda { + #[derive(Clone, Copy, Debug, PartialEq)]struct CONNECTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod txd { + mod ptr{ + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod maxcnt { + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod amount { + struct R; + impl R { } + impl R { } + impl R { } + } + mod list { + #[derive(Clone, Copy, Debug, PartialEq)]struct LISTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod events_stopped { + #[derive(Clone, Copy, Debug, PartialEq)]struct EVENTS_STOPPEDR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod events_rxstarted { + #[derive(Clone, Copy, Debug, PartialEq)]struct EVENTS_RXSTARTEDR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod events_write { + #[derive(Clone, Copy, Debug, PartialEq)]struct EVENTS_WRITER; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod shorts { + #[derive(Clone, Copy, Debug, PartialEq)]struct WRITE_SUSPENDR; + #[derive(Clone, Copy, Debug, PartialEq)]struct READ_SUSPENDR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod intenset { + #[derive(Clone, Copy, Debug, PartialEq)]struct STOPPEDR; + #[derive(Clone, Copy, Debug, PartialEq)]struct ERRORR; + #[derive(Clone, Copy, Debug, PartialEq)]struct RXSTARTEDR; + #[derive(Clone, Copy, Debug, PartialEq)]struct TXSTARTEDR; + #[derive(Clone, Copy, Debug, PartialEq)]struct WRITER; + #[derive(Clone, Copy, Debug, PartialEq)]struct READR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod errorsrc { + #[derive(Debug, PartialEq)]struct OVERFLOWR; + #[derive(Clone, Copy, Debug, PartialEq)]struct DNACKR; + #[derive(Clone, Copy, Debug, PartialEq)]struct OVERREADR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod enable { + #[derive(Clone, Copy, Debug, PartialEq)]struct ENABLER; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod config { + #[derive(Clone, Copy, Debug, PartialEq)]struct ADDRESS0R; + #[derive(Clone, Copy, Debug, PartialEq)]struct ADDRESS1R; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod spi0 { + mod psel { + mod sck { + #[derive(Clone, Copy, Debug, PartialEq)]struct CONNECTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + + } + mod mosi { + #[derive(Debug, PartialEq)]struct CONNECTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod miso { + #[derive(Debug, PartialEq)]struct CONNECTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod intenset { + #[derive(Debug, PartialEq)]struct READYR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod enable { + #[derive(Debug, PartialEq)]struct ENABLER; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod config { + #[derive(Clone, Copy, Debug, PartialEq)]struct ORDERR; + #[derive(Debug, PartialEq)]struct CPHAR; + #[derive(Clone, Copy, Debug, PartialEq)]struct CPOLR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod spim0 { + mod psel { + mod sck { + #[derive(Clone, Copy, Debug, PartialEq)]struct CONNECTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod mosi { + #[derive(Clone, Copy, Debug, PartialEq)]struct CONNECTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod miso { + #[derive(Clone, Copy, Debug, PartialEq)]struct CONNECTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod txd { + mod ptr { + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod maxcnt { + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod amount { + struct R; + impl R { } + impl R { } + impl R { } + } + mod list { + #[derive(Clone, Copy, Debug, PartialEq)]struct LISTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod tasks_resume { + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + } + mod events_stopped { + #[derive(Clone, Copy, Debug, PartialEq)]struct EVENTS_STOPPEDR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod events_end { + #[derive(Clone, Copy, Debug, PartialEq)]struct EVENTS_ENDR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod events_started { + #[derive(Clone, Copy, Debug, PartialEq)]struct EVENTS_STARTEDR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod intenset { + #[derive(Clone, Copy, Debug, PartialEq)]struct STOPPEDR; + #[derive(Clone, Copy, Debug, PartialEq)]struct ENDRXR; + #[derive(Clone, Copy, Debug, PartialEq)]struct ENDR; + #[derive(Clone, Copy, Debug, PartialEq)]struct ENDTXR; + #[derive(Clone, Copy, Debug, PartialEq)]struct STARTEDR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod intenclr { + #[derive(Clone, Copy, Debug, PartialEq)]struct STOPPEDR; + #[derive(Clone, Copy, Debug, PartialEq)]struct ENDRXR; + #[derive(Clone, Copy, Debug, PartialEq)]struct ENDR; + #[derive(Clone, Copy, Debug, PartialEq)]struct ENDTXR; + #[derive(Clone, Copy, Debug, PartialEq)]struct STARTEDR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod frequency { + #[derive(Clone, Copy, Debug, PartialEq)]struct FREQUENCYR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod spis0 { + mod psel { + mod sck { + #[derive(Clone, Copy, Debug, PartialEq)]struct CONNECTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod miso { + #[derive(Clone, Copy, Debug, PartialEq)]struct CONNECTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod mosi { + #[derive(Clone, Copy, Debug, PartialEq)]struct CONNECTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod csn { + #[derive(Clone, Copy, Debug, PartialEq)]struct CONNECTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod txd { + mod ptr { + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod maxcnt { + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod amount { + struct R; + impl R { } + impl R { } + impl R { } + } + mod list { + #[derive(Clone, Copy, Debug, PartialEq)]struct LISTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod events_endrx { + #[derive(Clone, Copy, Debug, PartialEq)]struct EVENTS_ENDRXR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod shorts { + #[derive(Clone, Copy, Debug, PartialEq)]struct END_ACQUIRER; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod intenclr { + #[derive(Clone, Copy, Debug, PartialEq)]struct ENDR; + #[derive(Clone, Copy, Debug, PartialEq)]struct ENDRXR; + #[derive(Clone, Copy, Debug, PartialEq)]struct ACQUIREDR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod status { + #[derive(Clone, Copy, Debug, PartialEq)]struct OVERREADR; + #[derive(Clone, Copy, Debug, PartialEq)]struct OVERFLOWR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod config { + #[derive(Clone, Copy, Debug, PartialEq)]struct ORDERR; + #[derive(Clone, Copy, Debug, PartialEq)]struct CPHAR; + #[derive(Clone, Copy, Debug, PartialEq)]struct CPOLR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + pub struct TIMER0; + mod timer0 { + mod shorts { + #[derive(Clone, Copy, Debug, PartialEq)]struct COMPARE0_CLEARR; + #[derive(Clone, Copy, Debug, PartialEq)]struct COMPARE1_CLEARR; + #[derive(Clone, Copy, Debug, PartialEq)]struct COMPARE2_CLEARR; + #[derive(Clone, Copy, Debug, PartialEq)]struct COMPARE3_CLEARR; + #[derive(Clone, Copy, Debug, PartialEq)]struct COMPARE4_CLEARR; + #[derive(Clone, Copy, Debug, PartialEq)]struct COMPARE5_CLEARR; + #[derive(Clone, Copy, Debug, PartialEq)]struct COMPARE0_STOPR; + #[derive(Clone, Copy, Debug, PartialEq)]struct COMPARE1_STOPR; + #[derive(Clone, Copy, Debug, PartialEq)]struct COMPARE2_STOPR; + #[derive(Clone, Copy, Debug, PartialEq)]struct COMPARE3_STOPR; + #[derive(Clone, Copy, Debug, PartialEq)]struct COMPARE4_STOPR; + #[derive(Clone, Copy, Debug, PartialEq)]struct COMPARE5_STOPR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod intenclr { + #[derive(Clone, Copy, Debug, PartialEq)]struct COMPARE0R; + #[derive(Clone, Copy, Debug, PartialEq)]struct COMPARE1R; + #[derive(Clone, Copy, Debug, PartialEq)]struct COMPARE2R; + #[derive(Clone, Copy, Debug, PartialEq)]struct COMPARE3R; + #[derive(Clone, Copy, Debug, PartialEq)]struct COMPARE4R; + #[derive(Clone, Copy, Debug, PartialEq)]struct COMPARE5R; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod bitmode { + #[derive(Clone, Copy, Debug, PartialEq)]struct BITMODER; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod temp { + mod events_datardy { + #[derive(Clone, Copy, Debug, PartialEq)]struct EVENTS_DATARDYR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod intenset { + #[derive(Clone, Copy, Debug, PartialEq)]struct DATARDYR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod rng { + mod events_valrdy { + #[derive(Clone, Copy, Debug, PartialEq)]struct EVENTS_VALRDYR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod intenset { + #[derive(Clone, Copy, Debug, PartialEq)]struct VALRDYR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod config { + #[derive(Clone, Copy, Debug, PartialEq)]struct DERCENR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod egu0 { + mod inten { + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED0R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED1R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED2R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED3R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED4R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED5R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED6R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED7R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED8R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED9R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED10R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED11R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED12R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED13R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED14R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED15R; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod intenclr { + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED0R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED1R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED2R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED3R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED4R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED5R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED6R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED7R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED8R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED9R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED10R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED11R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED12R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED13R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED14R; + #[derive(Clone, Copy, Debug, PartialEq)]struct TRIGGERED15R; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod pwm0 { + mod psel { + mod out { + #[derive(Clone, Copy, Debug, PartialEq)]struct CONNECTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod tasks_seqstart { + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + } + mod tasks_nextstep { + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + } + mod events_stopped { + #[derive(Clone, Copy, Debug, PartialEq)]struct EVENTS_STOPPEDR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod events_seqstarted { + #[derive(Clone, Copy, Debug, PartialEq)]struct EVENTS_SEQSTARTEDR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod events_seqend { + #[derive(Clone, Copy, Debug, PartialEq)]struct EVENTS_SEQENDR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod events_loopsdone { + #[derive(Clone, Copy, Debug, PartialEq)]struct EVENTS_LOOPSDONER; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod inten { + #[derive(Clone, Copy, Debug, PartialEq)]struct STOPPEDR; + #[derive(Clone, Copy, Debug, PartialEq)]struct SEQSTARTED0R; + #[derive(Clone, Copy, Debug, PartialEq)]struct SEQSTARTED1R; + #[derive(Clone, Copy, Debug, PartialEq)]struct SEQEND0R; + #[derive(Clone, Copy, Debug, PartialEq)]struct SEQEND1R; + #[derive(Clone, Copy, Debug, PartialEq)]struct PWMPERIODENDR; + #[derive(Clone, Copy, Debug, PartialEq)]struct LOOPSDONER; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod intenclr { + #[derive(Clone, Copy, Debug, PartialEq)]struct STOPPEDR; + #[derive(Clone, Copy, Debug, PartialEq)]struct SEQSTARTED0R; + #[derive(Clone, Copy, Debug, PartialEq)]struct SEQSTARTED1R; + #[derive(Clone, Copy, Debug, PartialEq)]struct SEQEND0R; + #[derive(Clone, Copy, Debug, PartialEq)]struct SEQEND1R; + #[derive(Clone, Copy, Debug, PartialEq)]struct PWMPERIODENDR; + #[derive(Clone, Copy, Debug, PartialEq)]struct LOOPSDONER; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod mode { + #[derive(Clone, Copy, Debug, PartialEq)]struct UPDOWNR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod prescaler { + #[derive(Clone, Copy, Debug, PartialEq)]struct PRESCALERR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + mod loop_ { + #[derive(Clone, Copy, Debug, PartialEq)]struct CNTR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod nvmc { + mod ready { + #[derive(Clone, Copy, Debug, PartialEq)]struct READYR; + struct R; + impl R { } + impl R { } + impl R { } + } + mod eraseuicr { + #[derive(Clone, Copy, Debug, PartialEq)]struct ERASEUICRR; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } + mod ppi { + mod chg { + #[derive(Clone, Copy, Debug, PartialEq)]struct CH0R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH1R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH2R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH3R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH4R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH5R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH6R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH7R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH8R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH9R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH10R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH11R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH12R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH13R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH14R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH15R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH16R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH17R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH18R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH19R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH20R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH21R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH22R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH23R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH24R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH25R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH26R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH27R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH28R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH29R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH30R; + #[derive(Clone, Copy, Debug, PartialEq)]struct CH31R; + struct R; + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + impl R { } + } + } +} diff --git a/src/test/run-make/removing-code-and-incremental-lto/rubble.rs.v1 b/src/test/run-make/removing-code-and-incremental-lto/rubble.rs.v1 new file mode 100644 index 0000000000000..5a85088411bca --- /dev/null +++ b/src/test/run-make/removing-code-and-incremental-lto/rubble.rs.v1 @@ -0,0 +1,61 @@ +#![no_std] +#![no_main] + +mod ble { + pub mod link { + #[cfg(not_now)] + pub fn process_data_packet() {} + + pub fn process_data_packet() { + use core::fmt::Write; + fn get() -> crate::ble::Duration { + unimplemented!() + } + let _ = write!(crate::Logger, "{}", get()); + } + } + + use core::fmt::{self, Debug, Display}; + + pub struct Duration(pub u32); + + impl Display for Duration { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.0 >= 1000 { + let (millis, submilli_micros) = (self.0 / 1000, self.0 % 1000); + write!(f, "{}", millis) + } else { + write!(f, "0") + } + } + } + + impl Debug for Duration { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(self, f) + } + } +} + +use core::fmt::{self, Write}; +use core::panic::PanicInfo; + +struct Logger; + +impl Write for Logger { + fn write_str(&mut self, _s: &str) -> fmt::Result { + loop { } + } +} + +#[export_name = "main"] +fn main() { + let _: nrf52810_hal::nrf52810_pac::TIMER0; + let _ = write!(Logger, "{:?}", None::); + crate::ble::link::process_data_packet(); +} + +#[panic_handler] +fn panic(_: &PanicInfo) -> ! { + loop {} +} diff --git a/src/test/run-make/removing-code-and-incremental-lto/rubble.rs.v2 b/src/test/run-make/removing-code-and-incremental-lto/rubble.rs.v2 new file mode 100644 index 0000000000000..df174f214dfc2 --- /dev/null +++ b/src/test/run-make/removing-code-and-incremental-lto/rubble.rs.v2 @@ -0,0 +1,65 @@ +#![no_std] +#![no_main] + +mod ble { + pub mod link { + pub fn process_data_packet() {} + + #[cfg(not_now)] + pub fn process_data_packet() { + use core::fmt::Write; + fn get() -> crate::ble::Duration { + unimplemented!() + } + let _ = write!(crate::Logger, "{}", get()); + } + } + + use core::fmt::{self, Debug, Display}; + + pub struct Duration(pub u32); + + impl Display for Duration { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.0 >= 1000 { + let (millis, submilli_micros) = (self.0 / 1000, self.0 % 1000); + if submilli_micros == 0 { + write!(f, "{}", millis) + } else { + write!(f, "{}{}", 0, 0) + } + } else { + write!(f, "0") + } + } + } + + impl Debug for Duration { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(self, f) + } + } +} + +use core::fmt::{self, Write}; +use core::panic::PanicInfo; + +struct Logger; + +impl Write for Logger { + fn write_str(&mut self, _s: &str) -> fmt::Result { + loop { } + } +} + +#[export_name = "main"] +fn main() { + let _: nrf52810_hal::nrf52810_pac::TIMER0; + let _ = write!(Logger, "{:?}", None::); + crate::ble::link::process_data_packet(); +} + +#[panic_handler] +fn panic(_: &PanicInfo) -> ! { + loop {} +} diff --git a/src/test/ui/associated-const/associated-const-ambiguity-report.stderr b/src/test/ui/associated-const/associated-const-ambiguity-report.stderr index bb217bd182db6..92a8d19021a2c 100644 --- a/src/test/ui/associated-const/associated-const-ambiguity-report.stderr +++ b/src/test/ui/associated-const/associated-const-ambiguity-report.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `Foo` for the type `i32` | LL | const ID: i32 = 1; | ^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `Foo::ID(...)` instead note: candidate #2 is defined in an impl of the trait `Bar` for the type `i32` --> $DIR/associated-const-ambiguity-report.rs:14:5 | LL | const ID: i32 = 3; | ^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `Bar::ID(...)` instead +help: disambiguate the associated constant for candidate #1 + | +LL | const X: i32 = Foo::ID; + | ^^^^^^^ +help: disambiguate the associated constant for candidate #2 + | +LL | const X: i32 = Bar::ID; + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0034.stderr b/src/test/ui/error-codes/E0034.stderr index a58d16bfafb59..6db2ef5051d83 100644 --- a/src/test/ui/error-codes/E0034.stderr +++ b/src/test/ui/error-codes/E0034.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `Trait1` for the type `Tes | LL | fn foo() {} | ^^^^^^^^ - = help: to disambiguate the method call, write `Trait1::foo(...)` instead note: candidate #2 is defined in an impl of the trait `Trait2` for the type `Test` --> $DIR/E0034.rs:16:5 | LL | fn foo() {} | ^^^^^^^^ - = help: to disambiguate the method call, write `Trait2::foo(...)` instead +help: disambiguate the method call for candidate #1 + | +LL | Trait1::foo() + | ^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | Trait2::foo() + | ^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/inference/inference_unstable_featured.stderr b/src/test/ui/inference/inference_unstable_featured.stderr index b06a6298a571c..fa908440e41ea 100644 --- a/src/test/ui/inference/inference_unstable_featured.stderr +++ b/src/test/ui/inference/inference_unstable_featured.stderr @@ -5,9 +5,15 @@ LL | assert_eq!('x'.ipu_flatten(), 0); | ^^^^^^^^^^^ multiple `ipu_flatten` found | = note: candidate #1 is defined in an impl of the trait `inference_unstable_iterator::IpuIterator` for the type `char` - = help: to disambiguate the method call, write `inference_unstable_iterator::IpuIterator::ipu_flatten('x')` instead = note: candidate #2 is defined in an impl of the trait `inference_unstable_itertools::IpuItertools` for the type `char` - = help: to disambiguate the method call, write `inference_unstable_itertools::IpuItertools::ipu_flatten('x')` instead +help: disambiguate the method call for candidate #1 + | +LL | assert_eq!(inference_unstable_iterator::IpuIterator::ipu_flatten(&'x'), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | assert_eq!(inference_unstable_itertools::IpuItertools::ipu_flatten(&'x'), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-18446.stderr b/src/test/ui/issues/issue-18446.stderr index e6afc4c13a912..3422add9dd96b 100644 --- a/src/test/ui/issues/issue-18446.stderr +++ b/src/test/ui/issues/issue-18446.stderr @@ -2,7 +2,10 @@ error[E0034]: multiple applicable items in scope --> $DIR/issue-18446.rs:18:7 | LL | x.foo(); - | ^^^ multiple `foo` found + | --^^^-- + | | | + | | multiple `foo` found + | help: disambiguate the method call for candidate #2: `T::foo(&x)` | note: candidate #1 is defined in an impl for the type `dyn T` --> $DIR/issue-18446.rs:9:5 @@ -14,7 +17,6 @@ note: candidate #2 is defined in the trait `T` | LL | fn foo(&self); | ^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `T::foo(&x)` instead error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3702-2.stderr b/src/test/ui/issues/issue-3702-2.stderr index 4d0ff750c254c..b18e407c3d464 100644 --- a/src/test/ui/issues/issue-3702-2.stderr +++ b/src/test/ui/issues/issue-3702-2.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `ToPrimitive` for the type | LL | fn to_int(&self) -> isize { 0 } | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `ToPrimitive::to_int(&self)` instead note: candidate #2 is defined in an impl of the trait `Add` for the type `isize` --> $DIR/issue-3702-2.rs:14:5 | LL | fn to_int(&self) -> isize { *self } | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `Add::to_int(&self)` instead +help: disambiguate the method call for candidate #1 + | +LL | ToPrimitive::to_int(&self) + other.to_int() + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | Add::to_int(&self) + other.to_int() + | ^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr b/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr index c7bb653dc1f14..feaf3dc753ffb 100644 --- a/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr +++ b/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `async` for the type `r#fn | LL | fn r#struct(&self) { | ^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `async::r#struct(r#fn {})` instead note: candidate #2 is defined in an impl of the trait `await` for the type `r#fn` --> $DIR/issue-65634-raw-ident-suggestion.rs:10:5 | LL | fn r#struct(&self) { | ^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `await::r#struct(r#fn {})` instead +help: disambiguate the method call for candidate #1 + | +LL | async::r#struct(&r#fn {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | await::r#struct(&r#fn {}); + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr index 9f46a722a508e..fa3add81a28f5 100644 --- a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr @@ -9,9 +9,15 @@ note: candidate #1 is defined in an impl of the trait `Me2` for the type `usize` | LL | impl Me2 for usize { fn me(&self) -> usize { *self } } | ^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `Me2::me(1_usize)` instead = note: candidate #2 is defined in an impl of the trait `ambig_impl_2_lib::Me` for the type `usize` - = help: to disambiguate the method call, write `ambig_impl_2_lib::Me::me(1_usize)` instead +help: disambiguate the method call for candidate #1 + | +LL | fn main() { Me2::me(&1_usize); } + | ^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | fn main() { ambig_impl_2_lib::Me::me(&1_usize); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr b/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr index 6c493c67e29d9..b6c81c2377ee4 100644 --- a/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-from-bounds.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in the trait `A` | LL | trait A { fn foo(&self); } | ^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `A::foo(t)` instead note: candidate #2 is defined in the trait `B` --> $DIR/method-ambig-two-traits-from-bounds.rs:2:11 | LL | trait B { fn foo(&self); } | ^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `B::foo(t)` instead +help: disambiguate the method call for candidate #1 + | +LL | A::foo(t); + | ^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | B::foo(t); + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr b/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr index 0b3724e030fa4..71c65f7ccc68d 100644 --- a/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-from-impls.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `A` for the type `AB` | LL | fn foo(self) {} | ^^^^^^^^^^^^ - = help: to disambiguate the method call, write `A::foo(AB {})` instead note: candidate #2 is defined in an impl of the trait `B` for the type `AB` --> $DIR/method-ambig-two-traits-from-impls.rs:11:5 | LL | fn foo(self) {} | ^^^^^^^^^^^^ - = help: to disambiguate the method call, write `B::foo(AB {})` instead +help: disambiguate the method call for candidate #1 + | +LL | A::foo(AB {}); + | ^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | B::foo(AB {}); + | ^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr index 81c99b33c813e..44f85071505d2 100644 --- a/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-from-impls2.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `A` for the type `AB` | LL | fn foo() {} | ^^^^^^^^ - = help: to disambiguate the method call, write `A::foo(...)` instead note: candidate #2 is defined in an impl of the trait `B` for the type `AB` --> $DIR/method-ambig-two-traits-from-impls2.rs:11:5 | LL | fn foo() {} | ^^^^^^^^ - = help: to disambiguate the method call, write `B::foo(...)` instead +help: disambiguate the method call for candidate #1 + | +LL | A::foo(); + | ^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | B::foo(); + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr b/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr index dc8aef2503739..3dbb17371004a 100644 --- a/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-with-default-method.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `Foo` for the type `usize` | LL | trait Foo { fn method(&self) {} } | ^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `Foo::method(1_usize)` instead note: candidate #2 is defined in an impl of the trait `Bar` for the type `usize` --> $DIR/method-ambig-two-traits-with-default-method.rs:6:13 | LL | trait Bar { fn method(&self) {} } | ^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `Bar::method(1_usize)` instead +help: disambiguate the method call for candidate #1 + | +LL | Foo::method(&1_usize); + | ^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | Bar::method(&1_usize); + | ^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr index c9d7da84e09f4..e7f295df8c482 100644 --- a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr +++ b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr @@ -25,19 +25,28 @@ note: candidate #1 is defined in an impl of the trait `internal::X` for the type | LL | fn foo(self: Smaht) -> u64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `internal::X::foo(x)` instead note: candidate #2 is defined in an impl of the trait `nuisance_foo::NuisanceFoo` for the type `_` --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:70:9 | LL | fn foo(self) {} | ^^^^^^^^^^^^ - = help: to disambiguate the method call, write `nuisance_foo::NuisanceFoo::foo(x)` instead note: candidate #3 is defined in the trait `FinalFoo` --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:57:5 | LL | fn foo(&self) -> u8; | ^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `FinalFoo::foo(x)` instead +help: disambiguate the method call for candidate #1 + | +LL | let z = internal::X::foo(x); + | ^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | let z = nuisance_foo::NuisanceFoo::foo(x); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #3 + | +LL | let z = FinalFoo::foo(x); + | ^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:137:24 diff --git a/src/test/ui/span/issue-37767.stderr b/src/test/ui/span/issue-37767.stderr index 0bbff45436c23..9ed6c8b826f79 100644 --- a/src/test/ui/span/issue-37767.stderr +++ b/src/test/ui/span/issue-37767.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in the trait `A` | LL | fn foo(&mut self) {} | ^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `A::foo(&a)` instead note: candidate #2 is defined in the trait `B` --> $DIR/issue-37767.rs:6:5 | LL | fn foo(&mut self) {} | ^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `B::foo(&a)` instead +help: disambiguate the method call for candidate #1 + | +LL | A::foo(&a) + | ^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | B::foo(&a) + | ^^^^^^^^^^ error[E0034]: multiple applicable items in scope --> $DIR/issue-37767.rs:22:7 @@ -28,13 +34,19 @@ note: candidate #1 is defined in the trait `C` | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `C::foo(&a)` instead note: candidate #2 is defined in the trait `D` --> $DIR/issue-37767.rs:18:5 | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `D::foo(&a)` instead +help: disambiguate the method call for candidate #1 + | +LL | C::foo(&a) + | ^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | D::foo(&a) + | ^^^^^^^^^^ error[E0034]: multiple applicable items in scope --> $DIR/issue-37767.rs:34:7 @@ -47,13 +59,19 @@ note: candidate #1 is defined in the trait `E` | LL | fn foo(self) {} | ^^^^^^^^^^^^ - = help: to disambiguate the method call, write `E::foo(a)` instead note: candidate #2 is defined in the trait `F` --> $DIR/issue-37767.rs:30:5 | LL | fn foo(self) {} | ^^^^^^^^^^^^ - = help: to disambiguate the method call, write `F::foo(a)` instead +help: disambiguate the method call for candidate #1 + | +LL | E::foo(a) + | ^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | F::foo(a) + | ^^^^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/span/issue-7575.stderr b/src/test/ui/span/issue-7575.stderr index 36db5bea86294..53a6238422b57 100644 --- a/src/test/ui/span/issue-7575.stderr +++ b/src/test/ui/span/issue-7575.stderr @@ -10,24 +10,33 @@ note: candidate #1 is defined in the trait `CtxtFn` | LL | fn f9(_: usize) -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `CtxtFn::f9(u, 342)` instead note: candidate #2 is defined in the trait `OtherTrait` --> $DIR/issue-7575.rs:8:5 | LL | fn f9(_: usize) -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `OtherTrait::f9(u, 342)` instead note: candidate #3 is defined in the trait `UnusedTrait` --> $DIR/issue-7575.rs:17:5 | LL | fn f9(_: usize) -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `UnusedTrait::f9(u, 342)` instead = help: items from traits can only be used if the trait is implemented and in scope = note: the following traits define an item `f9`, perhaps you need to implement one of them: candidate #1: `CtxtFn` candidate #2: `OtherTrait` candidate #3: `UnusedTrait` +help: disambiguate the method call for candidate #1 + | +LL | u.f8(42) + CtxtFn::f9(u, 342) + m.fff(42) + | ^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | u.f8(42) + OtherTrait::f9(u, 342) + m.fff(42) + | ^^^^^^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #3 + | +LL | u.f8(42) + UnusedTrait::f9(u, 342) + m.fff(42) + | ^^^^^^^^^^^^^^^^^^^^^^^ error[E0599]: no method named `fff` found for type `Myisize` in the current scope --> $DIR/issue-7575.rs:62:30 @@ -60,8 +69,11 @@ note: the candidate is defined in the trait `ManyImplTrait` | LL | fn is_str() -> bool { | ^^^^^^^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `ManyImplTrait::is_str(t)` instead = help: items from traits can only be used if the type parameter is bounded by the trait +help: disambiguate the method call for the candidate + | +LL | ManyImplTrait::is_str(t) + | help: the following trait defines an item `is_str`, perhaps you need to restrict type parameter `T` with it: | LL | fn param_bound(t: T) -> bool { diff --git a/src/test/ui/traits/trait-alias-ambiguous.stderr b/src/test/ui/traits/trait-alias-ambiguous.stderr index cde7dd0824924..48a029104aeca 100644 --- a/src/test/ui/traits/trait-alias-ambiguous.stderr +++ b/src/test/ui/traits/trait-alias-ambiguous.stderr @@ -9,13 +9,19 @@ note: candidate #1 is defined in an impl of the trait `inner::A` for the type `u | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `inner::A::foo(t)` instead note: candidate #2 is defined in an impl of the trait `inner::B` for the type `u8` --> $DIR/trait-alias-ambiguous.rs:11:9 | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ - = help: to disambiguate the method call, write `inner::B::foo(t)` instead +help: disambiguate the method call for candidate #1 + | +LL | inner::A::foo(&t); + | ^^^^^^^^^^^^^^^^^ +help: disambiguate the method call for candidate #2 + | +LL | inner::B::foo(&t); + | ^^^^^^^^^^^^^^^^^ error: aborting due to previous error