diff --git a/compiler/rustc_middle/src/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs index 81230e32f56bd..068f81486118a 100644 --- a/compiler/rustc_middle/src/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query/mod.rs @@ -232,6 +232,7 @@ macro_rules! define_callbacks { } pub trait QueryEngine<'tcx>: rustc_data_structures::sync::Sync { + #[cfg(parallel_compiler)] unsafe fn deadlock(&'tcx self, tcx: TyCtxt<'tcx>, registry: &rustc_rayon_core::Registry); fn encode_query_results( diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs index 88122777d2e67..85c5ee717481f 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs @@ -6,7 +6,7 @@ use rustc_middle::mir::{Mutability, Place, PlaceRef, ProjectionElem}; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::{ hir::place::PlaceBase, - mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, Location}, + mir::{self, ClearCrossCrate, Local, LocalDecl, LocalInfo, LocalKind, Location}, }; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::{kw, Symbol}; @@ -424,15 +424,28 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { match label { Some((true, err_help_span, suggested_code)) => { - err.span_suggestion( - err_help_span, - &format!( - "consider changing this to be a mutable {}", - pointer_desc - ), - suggested_code, - Applicability::MachineApplicable, - ); + let (is_trait_sig, local_trait) = self.is_error_in_trait(local); + if !is_trait_sig { + err.span_suggestion( + err_help_span, + &format!( + "consider changing this to be a mutable {}", + pointer_desc + ), + suggested_code, + Applicability::MachineApplicable, + ); + } else if let Some(x) = local_trait { + err.span_suggestion( + x, + &format!( + "consider changing that to be a mutable {}", + pointer_desc + ), + suggested_code, + Applicability::MachineApplicable, + ); + } } Some((false, err_label_span, message)) => { err.span_label(err_label_span, &message); @@ -502,6 +515,69 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { err.buffer(&mut self.errors_buffer); } + + /// User cannot make signature of a trait mutable without changing the + /// trait. So we find if this error belongs to a trait and if so we move + /// suggestion to the trait or disable it if it is out of scope of this crate + fn is_error_in_trait(&self, local: Local) -> (bool, Option) { + if self.body.local_kind(local) != LocalKind::Arg { + return (false, None); + } + let hir_map = self.infcx.tcx.hir(); + let my_def = self.body.source.def_id(); + let my_hir = hir_map.local_def_id_to_hir_id(my_def.as_local().unwrap()); + let td = if let Some(a) = self.infcx.tcx.impl_of_method(my_def).and_then(|x| { + self.infcx.tcx.trait_id_of_impl(x) + }) { + a + } else { + return (false, None); + }; + (true, td.as_local().and_then(|tld| { + let h = hir_map.local_def_id_to_hir_id(tld); + match hir_map.find(h) { + Some(Node::Item(hir::Item { + kind: hir::ItemKind::Trait( + _, _, _, _, + items + ), + .. + })) => { + let mut f_in_trait_opt = None; + for hir::TraitItemRef { id: fi, kind: k, .. } in *items { + let hi = fi.hir_id(); + if !matches!(k, hir::AssocItemKind::Fn { .. }) { + continue; + } + if hir_map.name(hi) != hir_map.name(my_hir) { + continue; + } + f_in_trait_opt = Some(hi); + break; + } + f_in_trait_opt.and_then(|f_in_trait| { + match hir_map.find(f_in_trait) { + Some(Node::TraitItem(hir::TraitItem { + kind: hir::TraitItemKind::Fn(hir::FnSig { + decl: hir::FnDecl { + inputs, + .. + }, + .. + }, _), + .. + })) => { + let hir::Ty { span, .. } = inputs[local.index() - 1]; + Some(span) + }, + _ => None, + } + }) + } + _ => None + } + })) + } // point to span of upvar making closure call require mutable borrow fn show_mutating_upvar( diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index ee914fa1ba95c..c789aa2fa596e 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -550,12 +550,10 @@ macro_rules! define_queries_struct { } impl QueryEngine<'tcx> for Queries<'tcx> { - unsafe fn deadlock(&'tcx self, _tcx: TyCtxt<'tcx>, _registry: &rustc_rayon_core::Registry) { - #[cfg(parallel_compiler)] - { - let tcx = QueryCtxt { tcx: _tcx, queries: self }; - rustc_query_system::query::deadlock(tcx, _registry) - } + #[cfg(parallel_compiler)] + unsafe fn deadlock(&'tcx self, tcx: TyCtxt<'tcx>, registry: &rustc_rayon_core::Registry) { + let tcx = QueryCtxt { tcx, queries: self }; + rustc_query_system::query::deadlock(tcx, registry) } fn encode_query_results( diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 68d2d619aabb4..39dfdd78cc4f5 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -605,13 +605,19 @@ fn incremental_verify_ich( let old_hash = tcx.dep_graph().prev_fingerprint_of(dep_node); - assert_eq!( - Some(new_hash), - old_hash, - "found unstable fingerprints for {:?}: {:?}", - dep_node, - result - ); + if Some(new_hash) != old_hash { + let run_cmd = if let Some(crate_name) = &tcx.sess().opts.crate_name { + format!("`cargo clean -p {}` or `cargo clean`", crate_name) + } else { + "`cargo clean`".to_string() + }; + tcx.sess().struct_err(&format!("internal compiler error: encountered incremental compilation error with {:?}", dep_node)) + .help(&format!("This is a known issue with the compiler. Run {} to allow your project to compile", run_cmd)) + .note(&format!("Please follow the instructions below to create a bug report with the provided information")) + .note(&format!("See for more information")) + .emit(); + panic!("Found unstable fingerprints for {:?}: {:?}", dep_node, result); + } } fn force_query_with_job( diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs index ca001635a3dc2..d3eb9fd955714 100644 --- a/compiler/rustc_ty_utils/src/representability.rs +++ b/compiler/rustc_ty_utils/src/representability.rs @@ -25,11 +25,26 @@ pub enum Representability { pub fn ty_is_representable<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, sp: Span) -> Representability { debug!("is_type_representable: {:?}", ty); // To avoid a stack overflow when checking an enum variant or struct that - // contains a different, structurally recursive type, maintain a stack - // of seen types and check recursion for each of them (issues #3008, #3779). + // contains a different, structurally recursive type, maintain a stack of + // seen types and check recursion for each of them (issues #3008, #3779, + // #74224, #84611). `shadow_seen` contains the full stack and `seen` only + // the one for the current type (e.g. if we have structs A and B, B contains + // a field of type A, and we're currently looking at B, then `seen` will be + // cleared when recursing to check A, but `shadow_seen` won't, so that we + // can catch cases of mutual recursion where A also contains B). let mut seen: Vec> = Vec::new(); + let mut shadow_seen: Vec<&'tcx ty::AdtDef> = Vec::new(); let mut representable_cache = FxHashMap::default(); - let r = is_type_structurally_recursive(tcx, sp, &mut seen, &mut representable_cache, ty); + let mut force_result = false; + let r = is_type_structurally_recursive( + tcx, + sp, + &mut seen, + &mut shadow_seen, + &mut representable_cache, + ty, + &mut force_result, + ); debug!("is_type_representable: {:?} is {:?}", ty, r); r } @@ -48,21 +63,38 @@ fn are_inner_types_recursive<'tcx>( tcx: TyCtxt<'tcx>, sp: Span, seen: &mut Vec>, + shadow_seen: &mut Vec<&'tcx ty::AdtDef>, representable_cache: &mut FxHashMap, Representability>, ty: Ty<'tcx>, + force_result: &mut bool, ) -> Representability { + debug!("are_inner_types_recursive({:?}, {:?}, {:?})", ty, seen, shadow_seen); match ty.kind() { ty::Tuple(..) => { // Find non representable - fold_repr( - ty.tuple_fields().map(|ty| { - is_type_structurally_recursive(tcx, sp, seen, representable_cache, ty) - }), - ) + fold_repr(ty.tuple_fields().map(|ty| { + is_type_structurally_recursive( + tcx, + sp, + seen, + shadow_seen, + representable_cache, + ty, + force_result, + ) + })) } // Fixed-length vectors. // FIXME(#11924) Behavior undecided for zero-length vectors. - ty::Array(ty, _) => is_type_structurally_recursive(tcx, sp, seen, representable_cache, ty), + ty::Array(ty, _) => is_type_structurally_recursive( + tcx, + sp, + seen, + shadow_seen, + representable_cache, + ty, + force_result, + ), ty::Adt(def, substs) => { // Find non representable fields with their spans fold_repr(def.all_fields().map(|field| { @@ -76,12 +108,128 @@ fn are_inner_types_recursive<'tcx>( Some(hir::Node::Field(field)) => field.ty.span, _ => sp, }; - match is_type_structurally_recursive(tcx, span, seen, representable_cache, ty) { - Representability::SelfRecursive(_) => { - Representability::SelfRecursive(vec![span]) + + let mut result = None; + + // First, we check whether the field type per se is representable. + // This catches cases as in #74224 and #84611. There is a special + // case related to mutual recursion, though; consider this example: + // + // struct A { + // z: T, + // x: B, + // } + // + // struct B { + // y: A + // } + // + // Here, without the following special case, both A and B are + // ContainsRecursive, which is a problem because we only report + // errors for SelfRecursive. We fix this by detecting this special + // case (shadow_seen.first() is the type we are originally + // interested in, and if we ever encounter the same AdtDef again, + // we know that it must be SelfRecursive) and "forcibly" returning + // SelfRecursive (by setting force_result, which tells the calling + // invocations of are_inner_types_representable to forward the + // result without adjusting). + if shadow_seen.len() > seen.len() && shadow_seen.first() == Some(def) { + *force_result = true; + result = Some(Representability::SelfRecursive(vec![span])); + } + + if result == None { + result = Some(Representability::Representable); + + // Now, we check whether the field types per se are representable, e.g. + // for struct Foo { x: Option }, we first check whether Option<_> + // by itself is representable (which it is), and the nesting of Foo + // will be detected later. This is necessary for #74224 and #84611. + + // If we have encountered an ADT definition that we have not seen + // before (no need to check them twice), recurse to see whether that + // definition is SelfRecursive. If so, we must be ContainsRecursive. + if shadow_seen.len() > 1 + && !shadow_seen + .iter() + .take(shadow_seen.len() - 1) + .any(|seen_def| seen_def == def) + { + let adt_def_id = def.did; + let raw_adt_ty = tcx.type_of(adt_def_id); + debug!("are_inner_types_recursive: checking nested type: {:?}", raw_adt_ty); + + // Check independently whether the ADT is SelfRecursive. If so, + // we must be ContainsRecursive (except for the special case + // mentioned above). + let mut nested_seen: Vec> = vec![]; + result = Some( + match is_type_structurally_recursive( + tcx, + span, + &mut nested_seen, + shadow_seen, + representable_cache, + raw_adt_ty, + force_result, + ) { + Representability::SelfRecursive(_) => { + if *force_result { + Representability::SelfRecursive(vec![span]) + } else { + Representability::ContainsRecursive + } + } + x => x, + }, + ); + } + + // We only enter the following block if the type looks representable + // so far. This is necessary for cases such as this one (#74224): + // + // struct A { + // x: T, + // y: A>, + // } + // + // struct B { + // z: A + // } + // + // When checking B, we recurse into A and check field y of type + // A>. We haven't seen this exact type before, so we recurse + // into A>, which contains, A>>, and so forth, + // ad infinitum. We can prevent this from happening by first checking + // A separately (the code above) and only checking for nested Bs if + // A actually looks representable (which it wouldn't in this example). + if result == Some(Representability::Representable) { + // Now, even if the type is representable (e.g. Option<_>), + // it might still contribute to a recursive type, e.g.: + // struct Foo { x: Option> } + // These cases are handled by passing the full `seen` + // stack to is_type_structurally_recursive (instead of the + // empty `nested_seen` above): + result = Some( + match is_type_structurally_recursive( + tcx, + span, + seen, + shadow_seen, + representable_cache, + ty, + force_result, + ) { + Representability::SelfRecursive(_) => { + Representability::SelfRecursive(vec![span]) + } + x => x, + }, + ); } - x => x, } + + result.unwrap() })) } ty::Closure(..) => { @@ -106,8 +254,10 @@ fn is_type_structurally_recursive<'tcx>( tcx: TyCtxt<'tcx>, sp: Span, seen: &mut Vec>, + shadow_seen: &mut Vec<&'tcx ty::AdtDef>, representable_cache: &mut FxHashMap, Representability>, ty: Ty<'tcx>, + force_result: &mut bool, ) -> Representability { debug!("is_type_structurally_recursive: {:?} {:?}", ty, sp); if let Some(representability) = representable_cache.get(ty) { @@ -118,8 +268,15 @@ fn is_type_structurally_recursive<'tcx>( return representability.clone(); } - let representability = - is_type_structurally_recursive_inner(tcx, sp, seen, representable_cache, ty); + let representability = is_type_structurally_recursive_inner( + tcx, + sp, + seen, + shadow_seen, + representable_cache, + ty, + force_result, + ); representable_cache.insert(ty, representability.clone()); representability @@ -129,12 +286,16 @@ fn is_type_structurally_recursive_inner<'tcx>( tcx: TyCtxt<'tcx>, sp: Span, seen: &mut Vec>, + shadow_seen: &mut Vec<&'tcx ty::AdtDef>, representable_cache: &mut FxHashMap, Representability>, ty: Ty<'tcx>, + force_result: &mut bool, ) -> Representability { match ty.kind() { ty::Adt(def, _) => { { + debug!("is_type_structurally_recursive_inner: adt: {:?}, seen: {:?}", ty, seen); + // Iterate through stack of previously seen types. let mut iter = seen.iter(); @@ -158,8 +319,10 @@ fn is_type_structurally_recursive_inner<'tcx>( // will recurse infinitely for some inputs. // // It is important that we DO take generic parameters into account - // here, so that code like this is considered SelfRecursive, not - // ContainsRecursive: + // here, because nesting e.g. Options is allowed (as long as the + // definition of Option doesn't itself include an Option field, which + // would be a case of SelfRecursive above). The following, too, counts + // as SelfRecursive: // // struct Foo { Option> } @@ -174,13 +337,31 @@ fn is_type_structurally_recursive_inner<'tcx>( // For structs and enums, track all previously seen types by pushing them // onto the 'seen' stack. seen.push(ty); - let out = are_inner_types_recursive(tcx, sp, seen, representable_cache, ty); + shadow_seen.push(def); + let out = are_inner_types_recursive( + tcx, + sp, + seen, + shadow_seen, + representable_cache, + ty, + force_result, + ); + shadow_seen.pop(); seen.pop(); out } _ => { // No need to push in other cases. - are_inner_types_recursive(tcx, sp, seen, representable_cache, ty) + are_inner_types_recursive( + tcx, + sp, + seen, + shadow_seen, + representable_cache, + ty, + force_result, + ) } } } diff --git a/config.toml.example b/config.toml.example index 6e5584797b559..16952a5ced83e 100644 --- a/config.toml.example +++ b/config.toml.example @@ -372,8 +372,6 @@ changelog-seen = 2 # This is mostly useful for tools; if you have changes to `compiler/` they will be ignored. # # You can set this to "if-unchanged" to only download if `compiler/` has not been modified. -# -# FIXME(#82739): currently, this also uses the downloaded compiler for stage0, but that causes unnecessary rebuilds. #download-rustc = false # Number of codegen units to use for each compiler invocation. A value of 0 diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 964169a227f64..800952f7a5ece 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -1733,6 +1733,19 @@ impl fmt::Pointer for Rc { #[stable(feature = "from_for_ptrs", since = "1.6.0")] impl From for Rc { + /// Converts a generic type `T` into a `Rc` + /// + /// The conversion allocates on the heap and moves `t` + /// from the stack into it. + /// + /// # Example + /// ```rust + /// # use std::rc::Rc; + /// let x = 5; + /// let rc = Rc::new(5); + /// + /// assert_eq!(Rc::from(x), rc); + /// ``` fn from(t: T) -> Self { Rc::new(t) } diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 66a88e85fea39..2676b3bf8e005 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -648,6 +648,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS } if builder.config.rustc_parallel { cargo.rustflag("--cfg=parallel_compiler"); + cargo.rustdocflag("--cfg=parallel_compiler"); } if builder.config.rust_verify_llvm_ir { cargo.env("RUSTC_VERIFY_LLVM_IR", "1"); diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index d961e067db37c..80a60c79edfe4 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -91,6 +91,7 @@ pub enum Subcommand { paths: Vec, }, Format { + paths: Vec, check: bool, }, Doc { @@ -581,7 +582,7 @@ Arguments: Subcommand::Clean { all: matches.opt_present("all") } } - "fmt" => Subcommand::Format { check: matches.opt_present("check") }, + "fmt" => Subcommand::Format { check: matches.opt_present("check"), paths }, "dist" => Subcommand::Dist { paths }, "install" => Subcommand::Install { paths }, "run" | "r" => { diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs index d21e3408144fe..2408344487bb1 100644 --- a/src/bootstrap/format.rs +++ b/src/bootstrap/format.rs @@ -42,7 +42,7 @@ struct RustfmtConfig { ignore: Vec, } -pub fn format(build: &Build, check: bool) { +pub fn format(build: &Build, check: bool, paths: &[PathBuf]) { if build.config.dry_run { return; } @@ -118,8 +118,19 @@ pub fn format(build: &Build, check: bool) { .to_path_buf(); let src = build.src.clone(); let (tx, rx): (SyncSender, _) = std::sync::mpsc::sync_channel(128); - let walker = - WalkBuilder::new(src.clone()).types(matcher).overrides(ignore_fmt).build_parallel(); + let walker = match paths.get(0) { + Some(first) => { + let mut walker = WalkBuilder::new(first); + for path in &paths[1..] { + walker.add(path); + } + walker + } + None => WalkBuilder::new(src.clone()), + } + .types(matcher) + .overrides(ignore_fmt) + .build_parallel(); // there is a lot of blocking involved in spawning a child process and reading files to format. // spawn more processes than available concurrency to keep the CPU busy diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index 24da44b933abc..2960dd3df6bf4 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -478,8 +478,8 @@ impl Build { job::setup(self); } - if let Subcommand::Format { check } = self.config.cmd { - return format::format(self, check); + if let Subcommand::Format { check, paths } = &self.config.cmd { + return format::format(self, *check, &paths); } if let Subcommand::Clean { all } = self.config.cmd { diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index df467bebe7481..78163651158ed 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -889,7 +889,7 @@ help: to skip test's attempt to check tidiness, pass `--exclude src/tools/tidy` ); std::process::exit(1); } - crate::format::format(&builder.build, !builder.config.cmd.bless()); + crate::format::format(&builder.build, !builder.config.cmd.bless(), &[]); } } diff --git a/src/test/ui/structs-enums/struct-rec/issue-74224.rs b/src/test/ui/structs-enums/struct-rec/issue-74224.rs new file mode 100644 index 0000000000000..f3b72c5df7f70 --- /dev/null +++ b/src/test/ui/structs-enums/struct-rec/issue-74224.rs @@ -0,0 +1,11 @@ +struct A { +//~^ ERROR recursive type `A` has infinite size + x: T, + y: A>, +} + +struct B { + z: A +} + +fn main() {} diff --git a/src/test/ui/structs-enums/struct-rec/issue-74224.stderr b/src/test/ui/structs-enums/struct-rec/issue-74224.stderr new file mode 100644 index 0000000000000..d61ab1952f9f1 --- /dev/null +++ b/src/test/ui/structs-enums/struct-rec/issue-74224.stderr @@ -0,0 +1,17 @@ +error[E0072]: recursive type `A` has infinite size + --> $DIR/issue-74224.rs:1:1 + | +LL | struct A { + | ^^^^^^^^^^^ recursive type has infinite size +... +LL | y: A>, + | ------- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `A` representable + | +LL | y: Box>>, + | ^^^^ ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0072`. diff --git a/src/test/ui/structs-enums/struct-rec/issue-84611.rs b/src/test/ui/structs-enums/struct-rec/issue-84611.rs new file mode 100644 index 0000000000000..4c356af3eb8a3 --- /dev/null +++ b/src/test/ui/structs-enums/struct-rec/issue-84611.rs @@ -0,0 +1,11 @@ +struct Foo { +//~^ ERROR recursive type `Foo` has infinite size + x: Foo<[T; 1]>, + y: T, +} + +struct Bar { + x: Foo, +} + +fn main() {} diff --git a/src/test/ui/structs-enums/struct-rec/issue-84611.stderr b/src/test/ui/structs-enums/struct-rec/issue-84611.stderr new file mode 100644 index 0000000000000..0a898e5c46dbe --- /dev/null +++ b/src/test/ui/structs-enums/struct-rec/issue-84611.stderr @@ -0,0 +1,17 @@ +error[E0072]: recursive type `Foo` has infinite size + --> $DIR/issue-84611.rs:1:1 + | +LL | struct Foo { + | ^^^^^^^^^^^^^ recursive type has infinite size +LL | +LL | x: Foo<[T; 1]>, + | ----------- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Foo` representable + | +LL | x: Box>, + | ^^^^ ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0072`. diff --git a/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.rs b/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.rs new file mode 100644 index 0000000000000..cca97f43effc3 --- /dev/null +++ b/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.rs @@ -0,0 +1,23 @@ +struct A { +//~^ ERROR recursive type `A` has infinite size + x: T, + y: B, +} + +struct B { +//~^ ERROR recursive type `B` has infinite size + z: A +} + +struct C { +//~^ ERROR recursive type `C` has infinite size + x: T, + y: Option>>, +} + +struct D { +//~^ ERROR recursive type `D` has infinite size + z: Option>>, +} + +fn main() {} diff --git a/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr b/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr new file mode 100644 index 0000000000000..efc4ba93f0a2b --- /dev/null +++ b/src/test/ui/structs-enums/struct-rec/mutual-struct-recursion.stderr @@ -0,0 +1,59 @@ +error[E0072]: recursive type `A` has infinite size + --> $DIR/mutual-struct-recursion.rs:1:1 + | +LL | struct A { + | ^^^^^^^^^^^ recursive type has infinite size +... +LL | y: B, + | ---- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `A` representable + | +LL | y: Box>, + | ^^^^ ^ + +error[E0072]: recursive type `B` has infinite size + --> $DIR/mutual-struct-recursion.rs:7:1 + | +LL | struct B { + | ^^^^^^^^^^^ recursive type has infinite size +LL | +LL | z: A + | ---- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `B` representable + | +LL | z: Box> + | ^^^^ ^ + +error[E0072]: recursive type `C` has infinite size + --> $DIR/mutual-struct-recursion.rs:12:1 + | +LL | struct C { + | ^^^^^^^^^^^ recursive type has infinite size +... +LL | y: Option>>, + | -------------------- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `C` representable + | +LL | y: Box>>>, + | ^^^^ ^ + +error[E0072]: recursive type `D` has infinite size + --> $DIR/mutual-struct-recursion.rs:18:1 + | +LL | struct D { + | ^^^^^^^^^^^ recursive type has infinite size +LL | +LL | z: Option>>, + | -------------------- recursive without indirection + | +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `D` representable + | +LL | z: Box>>>, + | ^^^^ ^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0072`. diff --git a/src/test/ui/suggestions/issue-68049-1.rs b/src/test/ui/suggestions/issue-68049-1.rs new file mode 100644 index 0000000000000..9b9ae429aebdc --- /dev/null +++ b/src/test/ui/suggestions/issue-68049-1.rs @@ -0,0 +1,16 @@ +use std::alloc::{GlobalAlloc, Layout}; + +struct Test(u32); + +unsafe impl GlobalAlloc for Test { + unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { + self.0 += 1; + 0 as *mut u8 + } + + unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) { + unimplemented!(); + } +} + +fn main() { } diff --git a/src/test/ui/suggestions/issue-68049-1.stderr b/src/test/ui/suggestions/issue-68049-1.stderr new file mode 100644 index 0000000000000..32367d2d0cf21 --- /dev/null +++ b/src/test/ui/suggestions/issue-68049-1.stderr @@ -0,0 +1,9 @@ +error[E0594]: cannot assign to `self.0` which is behind a `&` reference + --> $DIR/issue-68049-1.rs:7:9 + | +LL | self.0 += 1; + | ^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0594`. diff --git a/src/test/ui/suggestions/issue-68049-2.rs b/src/test/ui/suggestions/issue-68049-2.rs new file mode 100644 index 0000000000000..22bb6b85d6ffe --- /dev/null +++ b/src/test/ui/suggestions/issue-68049-2.rs @@ -0,0 +1,21 @@ +trait Hello { + fn example(&self, input: &i32); // should suggest here +} + +struct Test1(i32); + +impl Hello for Test1 { + fn example(&self, input: &i32) { // should not suggest here + *input = self.0; + } +} + +struct Test2(i32); + +impl Hello for Test2 { + fn example(&self, input: &i32) { // should not suggest here + self.0 += *input; + } +} + +fn main() { } diff --git a/src/test/ui/suggestions/issue-68049-2.stderr b/src/test/ui/suggestions/issue-68049-2.stderr new file mode 100644 index 0000000000000..f10a83c68a81b --- /dev/null +++ b/src/test/ui/suggestions/issue-68049-2.stderr @@ -0,0 +1,21 @@ +error[E0594]: cannot assign to `*input` which is behind a `&` reference + --> $DIR/issue-68049-2.rs:9:7 + | +LL | fn example(&self, input: &i32); // should suggest here + | ---- help: consider changing that to be a mutable reference: `&mut i32` +... +LL | *input = self.0; + | ^^^^^^^^^^^^^^^ `input` is a `&` reference, so the data it refers to cannot be written + +error[E0594]: cannot assign to `self.0` which is behind a `&` reference + --> $DIR/issue-68049-2.rs:17:5 + | +LL | fn example(&self, input: &i32); // should suggest here + | ----- help: consider changing that to be a mutable reference: `&mut self` +... +LL | self.0 += *input; + | ^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0594`.