From cb4f8153d8285ac2bf2145c569c09014f3ba317d Mon Sep 17 00:00:00 2001 From: Charisee Date: Sat, 22 Apr 2023 01:00:36 +0000 Subject: [PATCH 01/26] Add GNU Property Note --- .../rustc_codegen_ssa/src/back/metadata.rs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index d5d843702c0..baf674cf9eb 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -12,6 +12,7 @@ use object::{ use snap::write::FrameEncoder; +use object::elf::NT_GNU_PROPERTY_TYPE_0; use rustc_data_structures::memmap::Mmap; use rustc_data_structures::owned_slice::try_slice_owned; use rustc_data_structures::sync::MetadataRef; @@ -93,6 +94,46 @@ pub(super) fn search_for_section<'a>( .map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e)) } +fn add_gnu_property_note( + file: &mut write::Object<'static>, + architecture: Architecture, + binary_format: BinaryFormat, +) { + // check bti protection + if binary_format != BinaryFormat::Elf + || !matches!(architecture, Architecture::X86_64 | Architecture::Aarch64) + { + return; + } + + let section = file.add_section( + file.segment_name(StandardSegment::Data).to_vec(), + b".note.gnu.property".to_vec(), + SectionKind::Note, + ); + let mut data: Vec = Vec::new(); + let n_namsz: u32 = 4; // Size of the n_name field + let n_descsz: u32 = 16; // Size of the n_desc field + let n_type: u32 = NT_GNU_PROPERTY_TYPE_0; // Type of note descriptor + let values = [n_namsz, n_descsz, n_type]; + values.map(|v| data.extend_from_slice(&(v.to_le_bytes()))); + data.push(b'G'); // Owner of the program property note + data.push(b'N'); + data.push(b'U'); + data.push(0); + let pr_type: u32 = match architecture { + Architecture::X86_64 => 0xc0000002, + Architecture::Aarch64 => 0xc0000000, + _ => unreachable!(), + }; + let pr_datasz: u32 = 4; //size of the pr_data field + let pr_data: u32 = 3; //program property descriptor + let pr_padding: u32 = 3; + let values = [pr_type, pr_datasz, pr_data, pr_padding]; + values.map(|v| data.extend_from_slice(&(v.to_le_bytes()))); + file.append_section_data(section, &data, 4); +} + pub(crate) fn create_object_file(sess: &Session) -> Option> { let endianness = match sess.target.options.endian { Endian::Little => Endianness::Little, @@ -205,6 +246,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option elf::ELFOSABI_NONE, }; let abi_version = 0; + add_gnu_property_note(&mut file, architecture, binary_format); file.flags = FileFlags::Elf { os_abi, abi_version, e_flags }; Some(file) } From fd8aa5ec7d26c8e08d13b38213391c757045e51d Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Wed, 19 Apr 2023 18:22:03 +1200 Subject: [PATCH 02/26] tweak "make mut" spans when assigning to locals --- .../src/diagnostics/mutability_errors.rs | 56 ++++++++++--------- tests/ui/array-slice-vec/slice-mut-2.stderr | 2 +- ...row-raw-address-of-deref-mutability.stderr | 4 +- .../borrowck-access-permissions.stderr | 6 +- tests/ui/borrowck/borrowck-issue-14498.stderr | 2 +- tests/ui/borrowck/issue-85765.stderr | 2 +- .../diagnostics/mut_ref.stderr | 2 +- tests/ui/did_you_mean/issue-40823.stderr | 2 +- tests/ui/error-codes/E0389.stderr | 2 +- tests/ui/issues/issue-51515.rs | 1 - tests/ui/issues/issue-51515.stderr | 6 +- tests/ui/nll/issue-47388.stderr | 2 +- 12 files changed, 46 insertions(+), 41 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 7558247948f..b861a4f2861 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1202,36 +1202,42 @@ fn suggest_ampmut<'tcx>( opt_assignment_rhs_span: Option, opt_ty_info: Option, ) -> (bool, Span, String) { + // if there is a RHS and it starts with a `&` from it, then check if it is + // mutable, and if not, put suggest putting `mut ` to make it mutable. + // we don't have to worry about lifetime annotations here because they are + // not valid when taking a reference. For example, the following is not valid Rust: + // + // let x: &i32 = &'a 5; + // ^^ lifetime annotation not allowed + // if let Some(assignment_rhs_span) = opt_assignment_rhs_span && let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span) + && let Some(stripped) = src.strip_prefix('&') { - let is_mutbl = |ty: &str| -> bool { - if let Some(rest) = ty.strip_prefix("mut") { - match rest.chars().next() { - // e.g. `&mut x` - Some(c) if c.is_whitespace() => true, - // e.g. `&mut(x)` - Some('(') => true, - // e.g. `&mut{x}` - Some('{') => true, - // e.g. `&mutablevar` - _ => false, - } - } else { - false + let is_mut = if let Some(rest) = stripped.trim_start().strip_prefix("mut") { + match rest.chars().next() { + // e.g. `&mut x` + Some(c) if c.is_whitespace() => true, + // e.g. `&mut(x)` + Some('(') => true, + // e.g. `&mut{x}` + Some('{') => true, + // e.g. `&mutablevar` + _ => false, } + } else { + false }; - if let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(char::is_whitespace)) { - let lt_name = &src[1..ws_pos]; - let ty = src[ws_pos..].trim_start(); - if !is_mutbl(ty) { - return (true, assignment_rhs_span, format!("&{lt_name} mut {ty}")); - } - } else if let Some(stripped) = src.strip_prefix('&') { - let stripped = stripped.trim_start(); - if !is_mutbl(stripped) { - return (true, assignment_rhs_span, format!("&mut {stripped}")); - } + // if the reference is already mutable then there is nothing we can do + // here. + if !is_mut { + let span = assignment_rhs_span; + // shrink the span to just after the `&` in `&variable` + let span = span.with_lo(span.lo() + BytePos(1)).shrink_to_lo(); + + // FIXME(Ezrashaw): returning is bad because we still might want to + // update the annotated type, see #106857. + return (true, span, "mut ".to_owned()); } } diff --git a/tests/ui/array-slice-vec/slice-mut-2.stderr b/tests/ui/array-slice-vec/slice-mut-2.stderr index 5b040d3e4d3..c33919c41cd 100644 --- a/tests/ui/array-slice-vec/slice-mut-2.stderr +++ b/tests/ui/array-slice-vec/slice-mut-2.stderr @@ -7,7 +7,7 @@ LL | let _ = &mut x[2..4]; help: consider changing this to be a mutable reference | LL | let x: &[isize] = &mut [1, 2, 3, 4, 5]; - | ~~~~~~~~~~~~~~~~~~~~ + | +++ error: aborting due to previous error diff --git a/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr b/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr index 4cc1d821d0a..cfc86ff0dc1 100644 --- a/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr +++ b/tests/ui/borrowck/borrow-raw-address-of-deref-mutability.stderr @@ -7,7 +7,7 @@ LL | let q = &raw mut *x; help: consider changing this to be a mutable reference | LL | let x = &mut 0; - | ~~~~~~ + | +++ error[E0596]: cannot borrow `*x` as mutable, as it is behind a `*const` pointer --> $DIR/borrow-raw-address-of-deref-mutability.rs:14:13 @@ -18,7 +18,7 @@ LL | let q = &raw mut *x; help: consider changing this to be a mutable pointer | LL | let x = &mut 0 as *const i32; - | ~~~~~~ + | +++ error: aborting due to 2 previous errors diff --git a/tests/ui/borrowck/borrowck-access-permissions.stderr b/tests/ui/borrowck/borrowck-access-permissions.stderr index 26f3e2bbdb7..c161e2d95b4 100644 --- a/tests/ui/borrowck/borrowck-access-permissions.stderr +++ b/tests/ui/borrowck/borrowck-access-permissions.stderr @@ -35,7 +35,7 @@ LL | let _y1 = &mut *ref_x; help: consider changing this to be a mutable reference | LL | let ref_x = &mut x; - | ~~~~~~ + | +++ error[E0596]: cannot borrow `*ptr_x` as mutable, as it is behind a `*const` pointer --> $DIR/borrowck-access-permissions.rs:39:23 @@ -46,7 +46,7 @@ LL | let _y1 = &mut *ptr_x; help: consider changing this to be a mutable pointer | LL | let ptr_x : *const _ = &mut x; - | ~~~~~~ + | +++ error[E0596]: cannot borrow `*foo_ref.f` as mutable, as it is behind a `&` reference --> $DIR/borrowck-access-permissions.rs:48:18 @@ -57,7 +57,7 @@ LL | let _y = &mut *foo_ref.f; help: consider changing this to be a mutable reference | LL | let foo_ref = &mut foo; - | ~~~~~~~~ + | +++ error: aborting due to 6 previous errors diff --git a/tests/ui/borrowck/borrowck-issue-14498.stderr b/tests/ui/borrowck/borrowck-issue-14498.stderr index 374c5ee3ed2..12d67d536d9 100644 --- a/tests/ui/borrowck/borrowck-issue-14498.stderr +++ b/tests/ui/borrowck/borrowck-issue-14498.stderr @@ -7,7 +7,7 @@ LL | ***p = 2; help: consider changing this to be a mutable reference | LL | let p = &mut y; - | ~~~~~~ + | +++ error[E0506]: cannot assign to `**y` because it is borrowed --> $DIR/borrowck-issue-14498.rs:25:5 diff --git a/tests/ui/borrowck/issue-85765.stderr b/tests/ui/borrowck/issue-85765.stderr index b4bb128cbb4..2985a658fdd 100644 --- a/tests/ui/borrowck/issue-85765.stderr +++ b/tests/ui/borrowck/issue-85765.stderr @@ -18,7 +18,7 @@ LL | *r = 0; help: consider changing this to be a mutable reference | LL | let r = &mut mutvar; - | ~~~~~~~~~~~ + | +++ error[E0594]: cannot assign to `*x`, which is behind a `&` reference --> $DIR/issue-85765.rs:19:5 diff --git a/tests/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr b/tests/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr index 95f36fc042c..1904faa9598 100644 --- a/tests/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr +++ b/tests/ui/closures/2229_closure_analysis/diagnostics/mut_ref.stderr @@ -10,7 +10,7 @@ LL | **ref_mref_x = y; help: consider changing this to be a mutable reference | LL | let ref_mref_x = &mut mref_x; - | ~~~~~~~~~~~ + | +++ error[E0596]: cannot borrow `**mref_ref_x` as mutable, as it is behind a `&` reference --> $DIR/mut_ref.rs:26:13 diff --git a/tests/ui/did_you_mean/issue-40823.stderr b/tests/ui/did_you_mean/issue-40823.stderr index aadd698891e..ba94a570256 100644 --- a/tests/ui/did_you_mean/issue-40823.stderr +++ b/tests/ui/did_you_mean/issue-40823.stderr @@ -7,7 +7,7 @@ LL | buf.iter_mut(); help: consider changing this to be a mutable reference | LL | let mut buf = &mut [1, 2, 3, 4]; - | ~~~~~~~~~~~~~~~~~ + | +++ error: aborting due to previous error diff --git a/tests/ui/error-codes/E0389.stderr b/tests/ui/error-codes/E0389.stderr index 51c4c92addf..e4001856c38 100644 --- a/tests/ui/error-codes/E0389.stderr +++ b/tests/ui/error-codes/E0389.stderr @@ -7,7 +7,7 @@ LL | fancy_ref.num = 6; help: consider changing this to be a mutable reference | LL | let fancy_ref = &mut (&mut fancy); - | ~~~~~~~~~~~~~~~~~ + | +++ error: aborting due to previous error diff --git a/tests/ui/issues/issue-51515.rs b/tests/ui/issues/issue-51515.rs index 84e09afac0a..33a9bf85e23 100644 --- a/tests/ui/issues/issue-51515.rs +++ b/tests/ui/issues/issue-51515.rs @@ -1,7 +1,6 @@ fn main() { let foo = &16; //~^ HELP consider changing this to be a mutable reference - //~| SUGGESTION &mut 16 *foo = 32; //~^ ERROR cannot assign to `*foo`, which is behind a `&` reference let bar = foo; diff --git a/tests/ui/issues/issue-51515.stderr b/tests/ui/issues/issue-51515.stderr index 94e5c9f1b83..88b8d210908 100644 --- a/tests/ui/issues/issue-51515.stderr +++ b/tests/ui/issues/issue-51515.stderr @@ -1,5 +1,5 @@ error[E0594]: cannot assign to `*foo`, which is behind a `&` reference - --> $DIR/issue-51515.rs:5:5 + --> $DIR/issue-51515.rs:4:5 | LL | *foo = 32; | ^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written @@ -7,10 +7,10 @@ LL | *foo = 32; help: consider changing this to be a mutable reference | LL | let foo = &mut 16; - | ~~~~~~~ + | +++ error[E0594]: cannot assign to `*bar`, which is behind a `&` reference - --> $DIR/issue-51515.rs:9:5 + --> $DIR/issue-51515.rs:8:5 | LL | *bar = 64; | ^^^^^^^^^ `bar` is a `&` reference, so the data it refers to cannot be written diff --git a/tests/ui/nll/issue-47388.stderr b/tests/ui/nll/issue-47388.stderr index c780451dfa9..09b9d638afb 100644 --- a/tests/ui/nll/issue-47388.stderr +++ b/tests/ui/nll/issue-47388.stderr @@ -7,7 +7,7 @@ LL | fancy_ref.num = 6; help: consider changing this to be a mutable reference | LL | let fancy_ref = &mut (&mut fancy); - | ~~~~~~~~~~~~~~~~~ + | +++ error: aborting due to previous error From 9624d2b08e87995978899f236db1857e85097b37 Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Wed, 19 Apr 2023 19:29:28 +1200 Subject: [PATCH 03/26] tweak "make mut" spans (No. 2) --- .../src/diagnostics/mutability_errors.rs | 48 +++++++++++-------- tests/ui/did_you_mean/issue-39544.stderr | 2 +- tests/ui/issues/issue-61623.stderr | 2 +- ...ck-borrow-overloaded-auto-deref-mut.stderr | 4 +- ...orrowck-borrow-overloaded-deref-mut.stderr | 4 +- tests/ui/span/mut-arg-hint.stderr | 2 +- ...l-bounds-inconsistent-copy-reborrow.stderr | 4 +- 7 files changed, 36 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index b861a4f2861..27f700ebbda 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1241,35 +1241,41 @@ fn suggest_ampmut<'tcx>( } } - let (suggestibility, highlight_span) = match opt_ty_info { + let (binding_exists, span) = match opt_ty_info { // if this is a variable binding with an explicit type, - // try to highlight that for the suggestion. + // then we will suggest changing it to be mutable. + // this is `Applicability::MachineApplicable`. Some(ty_span) => (true, ty_span), - // otherwise, just highlight the span associated with - // the (MIR) LocalDecl. + // otherwise, we'll suggest *adding* an annotated type, we'll suggest + // the RHS's type for that. + // this is `Applicability::HasPlaceholders`. None => (false, local_decl.source_info.span), }; - if let Ok(src) = tcx.sess.source_map().span_to_snippet(highlight_span) - && let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(char::is_whitespace)) + // if the binding already exists and is a reference with a explicit + // lifetime, then we can suggest adding ` mut`. this is special-cased from + // the path without a explicit lifetime. + if let Ok(src) = tcx.sess.source_map().span_to_snippet(span) + && src.starts_with("&'") + // note that `& 'a T` is invalid so this is correct. + && let Some(ws_pos) = src.find(char::is_whitespace) { - let lt_name = &src[1..ws_pos]; - let ty = &src[ws_pos..]; - return (true, highlight_span, format!("&{lt_name} mut{ty}")); + let span = span.with_lo(span.lo() + BytePos(ws_pos as u32)).shrink_to_lo(); + (true, span, " mut".to_owned()) + } else { + let ty_mut = local_decl.ty.builtin_deref(true).unwrap(); + assert_eq!(ty_mut.mutbl, hir::Mutability::Not); + ( + binding_exists, + span, + if local_decl.ty.is_ref() { + format!("&mut {}", ty_mut.ty) + } else { + format!("*mut {}", ty_mut.ty) + }, + ) } - - let ty_mut = local_decl.ty.builtin_deref(true).unwrap(); - assert_eq!(ty_mut.mutbl, hir::Mutability::Not); - ( - suggestibility, - highlight_span, - if local_decl.ty.is_ref() { - format!("&mut {}", ty_mut.ty) - } else { - format!("*mut {}", ty_mut.ty) - }, - ) } fn is_closure_or_generator(ty: Ty<'_>) -> bool { diff --git a/tests/ui/did_you_mean/issue-39544.stderr b/tests/ui/did_you_mean/issue-39544.stderr index 8dc0512a945..97f0ec60603 100644 --- a/tests/ui/did_you_mean/issue-39544.stderr +++ b/tests/ui/did_you_mean/issue-39544.stderr @@ -73,7 +73,7 @@ LL | let _ = &mut self.x; help: consider changing this to be a mutable reference | LL | fn foo3<'a>(self: &'a mut Self, other: &Z) { - | ~~~~~~~~~~~~ + | +++ error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference --> $DIR/issue-39544.rs:31:17 diff --git a/tests/ui/issues/issue-61623.stderr b/tests/ui/issues/issue-61623.stderr index 5fcc338557c..bedea3890a3 100644 --- a/tests/ui/issues/issue-61623.stderr +++ b/tests/ui/issues/issue-61623.stderr @@ -7,7 +7,7 @@ LL | f2(|| x.0, f1(x.1)) help: consider changing this to be a mutable reference | LL | fn f3<'a>(x: &'a mut ((), &'a mut ())) { - | ~~~~~~~~~~~~~~~~~~~~~~~~ + | +++ error: aborting due to previous error diff --git a/tests/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr b/tests/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr index 570328fc211..e640d40913e 100644 --- a/tests/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr +++ b/tests/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr @@ -50,7 +50,7 @@ LL | x.y = 3; help: consider changing this to be a mutable reference | LL | fn assign_field2<'a>(x: &'a mut Own) { - | ~~~~~~~~~~~~~~~~~~ + | +++ error[E0499]: cannot borrow `*x` as mutable more than once at a time --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:101:5 @@ -104,7 +104,7 @@ LL | *x.y_mut() = 3; help: consider changing this to be a mutable reference | LL | fn assign_method2<'a>(x: &'a mut Own) { - | ~~~~~~~~~~~~~~~~~~ + | +++ error: aborting due to 10 previous errors diff --git a/tests/ui/span/borrowck-borrow-overloaded-deref-mut.stderr b/tests/ui/span/borrowck-borrow-overloaded-deref-mut.stderr index 3fed7b3f4dc..dbd52dc2d38 100644 --- a/tests/ui/span/borrowck-borrow-overloaded-deref-mut.stderr +++ b/tests/ui/span/borrowck-borrow-overloaded-deref-mut.stderr @@ -18,7 +18,7 @@ LL | &mut **x help: consider changing this to be a mutable reference | LL | fn deref_extend_mut1<'a>(x: &'a mut Own) -> &'a mut isize { - | ~~~~~~~~~~~~~~~~~~ + | +++ error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-borrow-overloaded-deref-mut.rs:49:6 @@ -40,7 +40,7 @@ LL | **x = 3; help: consider changing this to be a mutable reference | LL | fn assign2<'a>(x: &'a mut Own) { - | ~~~~~~~~~~~~~~~~~~ + | +++ error: aborting due to 4 previous errors diff --git a/tests/ui/span/mut-arg-hint.stderr b/tests/ui/span/mut-arg-hint.stderr index 96ce4d5bc6c..9b82012291c 100644 --- a/tests/ui/span/mut-arg-hint.stderr +++ b/tests/ui/span/mut-arg-hint.stderr @@ -18,7 +18,7 @@ LL | a.push_str("foo"); help: consider changing this to be a mutable reference | LL | pub fn foo<'a>(mut a: &'a mut String) { - | ~~~~~~~~~~~~~~ + | +++ error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/mut-arg-hint.rs:15:9 diff --git a/tests/ui/trivial-bounds/trivial-bounds-inconsistent-copy-reborrow.stderr b/tests/ui/trivial-bounds/trivial-bounds-inconsistent-copy-reborrow.stderr index 39b60c31197..c054ddb893d 100644 --- a/tests/ui/trivial-bounds/trivial-bounds-inconsistent-copy-reborrow.stderr +++ b/tests/ui/trivial-bounds/trivial-bounds-inconsistent-copy-reborrow.stderr @@ -7,7 +7,7 @@ LL | *t help: consider changing this to be a mutable reference | LL | fn reborrow_mut<'a>(t: &'a mut &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy { - | ~~~~~~~~~~~~~~~~~~~ + | +++ error[E0596]: cannot borrow `**t` as mutable, as it is behind a `&` reference --> $DIR/trivial-bounds-inconsistent-copy-reborrow.rs:10:6 @@ -18,7 +18,7 @@ LL | {*t} help: consider changing this to be a mutable reference | LL | fn copy_reborrow_mut<'a>(t: &'a mut &'a mut i32) -> &'a mut i32 where &'a mut i32: Copy { - | ~~~~~~~~~~~~~~~~~~~ + | +++ error: aborting due to 2 previous errors From 57c6a3183c17e9f889adda1faca894a7cd692b02 Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Wed, 19 Apr 2023 19:50:08 +1200 Subject: [PATCH 04/26] tweak "make mut" spans (No. 3) --- .../src/diagnostics/mutability_errors.rs | 4 ++++ ...k-assign-to-andmut-in-aliasable-loc.stderr | 8 +++---- ...orrow-mut-base-ptr-in-aliasable-loc.stderr | 4 ++-- .../borrowck-reborrow-from-mut.stderr | 2 +- tests/ui/borrowck/mutability-errors.stderr | 24 +++++++++---------- tests/ui/did_you_mean/issue-38147-4.stderr | 4 ++-- tests/ui/did_you_mean/issue-39544.stderr | 10 ++++---- tests/ui/nll/issue-57989.stderr | 2 +- ...ck-borrow-overloaded-auto-deref-mut.stderr | 4 ++-- ...borrowck-call-is-borrow-issue-12224.stderr | 6 ++--- ...owck-call-method-from-mut-aliasable.stderr | 2 +- tests/ui/span/borrowck-fn-in-const-b.stderr | 2 +- .../ui/span/borrowck-object-mutability.stderr | 2 +- tests/ui/span/mut-arg-hint.stderr | 4 ++-- tests/ui/suggestions/issue-68049-2.stderr | 4 ++-- 15 files changed, 43 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 27f700ebbda..50f9e7095f9 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1263,6 +1263,10 @@ fn suggest_ampmut<'tcx>( { let span = span.with_lo(span.lo() + BytePos(ws_pos as u32)).shrink_to_lo(); (true, span, " mut".to_owned()) + } else if binding_exists { + // shrink the span to just after the `&` in `&variable` + let span = span.with_lo(span.lo() + BytePos(1)).shrink_to_lo(); + (true, span, "mut ".to_owned()) } else { let ty_mut = local_decl.ty.builtin_deref(true).unwrap(); assert_eq!(ty_mut.mutbl, hir::Mutability::Not); diff --git a/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr b/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr index cbacc87a0e8..cf0c4127d82 100644 --- a/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr +++ b/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr @@ -6,8 +6,8 @@ LL | *s.pointer += 1; | help: consider changing this to be a mutable reference | -LL | fn a(s: &mut S<'_>) { - | ~~~~~~~~~~ +LL | fn a(s: &mut S) { + | +++ error[E0594]: cannot assign to `*s.pointer`, which is behind a `&` reference --> $DIR/borrowck-assign-to-andmut-in-aliasable-loc.rs:17:5 @@ -17,8 +17,8 @@ LL | *s.pointer += 1; | help: consider changing this to be a mutable reference | -LL | fn c(s: &mut &mut S<'_>) { - | ~~~~~~~~~~~~~~~ +LL | fn c(s: &mut &mut S) { + | +++ error: aborting due to 2 previous errors diff --git a/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr b/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr index dd0817ff233..59ef61b19d5 100644 --- a/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr +++ b/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr @@ -27,8 +27,8 @@ LL | let x: &mut isize = &mut **t0; | help: consider changing this to be a mutable reference | -LL | fn foo4(t0: &mut &mut isize) { - | ~~~~~~~~~~~~~~~ +LL | fn foo4(t0: &mut &mut isize) { + | +++ error: aborting due to 3 previous errors diff --git a/tests/ui/borrowck/borrowck-reborrow-from-mut.stderr b/tests/ui/borrowck/borrowck-reborrow-from-mut.stderr index d9590e446c7..fb3db4e1446 100644 --- a/tests/ui/borrowck/borrowck-reborrow-from-mut.stderr +++ b/tests/ui/borrowck/borrowck-reborrow-from-mut.stderr @@ -111,7 +111,7 @@ LL | let _bar1 = &mut foo.bar1; help: consider changing this to be a mutable reference | LL | fn borrow_mut_from_imm(foo: &mut Foo) { - | ~~~~~~~~ + | +++ error: aborting due to 11 previous errors diff --git a/tests/ui/borrowck/mutability-errors.stderr b/tests/ui/borrowck/mutability-errors.stderr index d7c602718f1..b39e57d70ec 100644 --- a/tests/ui/borrowck/mutability-errors.stderr +++ b/tests/ui/borrowck/mutability-errors.stderr @@ -7,7 +7,7 @@ LL | *x = (1,); help: consider changing this to be a mutable reference | LL | fn named_ref(x: &mut (i32,)) { - | ~~~~~~~~~~~ + | +++ error[E0594]: cannot assign to `x.0`, which is behind a `&` reference --> $DIR/mutability-errors.rs:10:5 @@ -18,7 +18,7 @@ LL | x.0 = 1; help: consider changing this to be a mutable reference | LL | fn named_ref(x: &mut (i32,)) { - | ~~~~~~~~~~~ + | +++ error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/mutability-errors.rs:11:5 @@ -29,7 +29,7 @@ LL | &mut *x; help: consider changing this to be a mutable reference | LL | fn named_ref(x: &mut (i32,)) { - | ~~~~~~~~~~~ + | +++ error[E0596]: cannot borrow `x.0` as mutable, as it is behind a `&` reference --> $DIR/mutability-errors.rs:12:5 @@ -40,7 +40,7 @@ LL | &mut x.0; help: consider changing this to be a mutable reference | LL | fn named_ref(x: &mut (i32,)) { - | ~~~~~~~~~~~ + | +++ error[E0594]: cannot assign to data in a `&` reference --> $DIR/mutability-errors.rs:16:5 @@ -74,8 +74,8 @@ LL | *x = (1,); | help: consider changing this to be a mutable pointer | -LL | unsafe fn named_ptr(x: *mut (i32,)) { - | ~~~~~~~~~~~ +LL | unsafe fn named_ptr(x: *mut const (i32,)) { + | +++ error[E0594]: cannot assign to `x.0`, which is behind a `*const` pointer --> $DIR/mutability-errors.rs:24:5 @@ -85,8 +85,8 @@ LL | (*x).0 = 1; | help: consider changing this to be a mutable pointer | -LL | unsafe fn named_ptr(x: *mut (i32,)) { - | ~~~~~~~~~~~ +LL | unsafe fn named_ptr(x: *mut const (i32,)) { + | +++ error[E0596]: cannot borrow `*x` as mutable, as it is behind a `*const` pointer --> $DIR/mutability-errors.rs:25:5 @@ -96,8 +96,8 @@ LL | &mut *x; | help: consider changing this to be a mutable pointer | -LL | unsafe fn named_ptr(x: *mut (i32,)) { - | ~~~~~~~~~~~ +LL | unsafe fn named_ptr(x: *mut const (i32,)) { + | +++ error[E0596]: cannot borrow `x.0` as mutable, as it is behind a `*const` pointer --> $DIR/mutability-errors.rs:26:5 @@ -107,8 +107,8 @@ LL | &mut (*x).0; | help: consider changing this to be a mutable pointer | -LL | unsafe fn named_ptr(x: *mut (i32,)) { - | ~~~~~~~~~~~ +LL | unsafe fn named_ptr(x: *mut const (i32,)) { + | +++ error[E0594]: cannot assign to data in a `*const` pointer --> $DIR/mutability-errors.rs:30:5 diff --git a/tests/ui/did_you_mean/issue-38147-4.stderr b/tests/ui/did_you_mean/issue-38147-4.stderr index d3339989361..43647fa562b 100644 --- a/tests/ui/did_you_mean/issue-38147-4.stderr +++ b/tests/ui/did_you_mean/issue-38147-4.stderr @@ -6,8 +6,8 @@ LL | f.s.push('x'); | help: consider changing this to be a mutable reference | -LL | fn f(x: usize, f: &mut Foo<'_>) { - | ~~~~~~~~~~~~ +LL | fn f(x: usize, f: &mut Foo) { + | +++ error: aborting due to previous error diff --git a/tests/ui/did_you_mean/issue-39544.stderr b/tests/ui/did_you_mean/issue-39544.stderr index 97f0ec60603..8ccb4cbb0c1 100644 --- a/tests/ui/did_you_mean/issue-39544.stderr +++ b/tests/ui/did_you_mean/issue-39544.stderr @@ -40,7 +40,7 @@ LL | let _ = &mut other.x; help: consider changing this to be a mutable reference | LL | fn foo1(&self, other: &mut Z) { - | ~~~~~~ + | +++ error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference --> $DIR/issue-39544.rs:25:17 @@ -62,7 +62,7 @@ LL | let _ = &mut other.x; help: consider changing this to be a mutable reference | LL | fn foo2<'a>(&'a self, other: &mut Z) { - | ~~~~~~ + | +++ error[E0596]: cannot borrow `self.x` as mutable, as it is behind a `&` reference --> $DIR/issue-39544.rs:30:17 @@ -84,7 +84,7 @@ LL | let _ = &mut other.x; help: consider changing this to be a mutable reference | LL | fn foo3<'a>(self: &'a Self, other: &mut Z) { - | ~~~~~~ + | +++ error[E0596]: cannot borrow `other.x` as mutable, as it is behind a `&` reference --> $DIR/issue-39544.rs:35:17 @@ -95,7 +95,7 @@ LL | let _ = &mut other.x; help: consider changing this to be a mutable reference | LL | fn foo4(other: &mut Z) { - | ~~~~~~ + | +++ error[E0596]: cannot borrow `z.x` as mutable, as `z` is not declared as mutable --> $DIR/issue-39544.rs:41:13 @@ -117,7 +117,7 @@ LL | let _ = &mut w.x; help: consider changing this to be a mutable reference | LL | pub fn with_arg(z: Z, w: &mut Z) { - | ~~~~~~ + | +++ error[E0594]: cannot assign to `*x.0`, which is behind a `&` reference --> $DIR/issue-39544.rs:48:5 diff --git a/tests/ui/nll/issue-57989.stderr b/tests/ui/nll/issue-57989.stderr index d5effd6f346..6062b31d688 100644 --- a/tests/ui/nll/issue-57989.stderr +++ b/tests/ui/nll/issue-57989.stderr @@ -7,7 +7,7 @@ LL | *x = 0; help: consider changing this to be a mutable reference | LL | fn f(x: &mut i32) { - | ~~~~~~~~ + | +++ error[E0506]: cannot assign to `*x` because it is borrowed --> $DIR/issue-57989.rs:5:5 diff --git a/tests/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr b/tests/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr index e640d40913e..80c5f9da40c 100644 --- a/tests/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr +++ b/tests/ui/span/borrowck-borrow-overloaded-auto-deref-mut.stderr @@ -18,7 +18,7 @@ LL | &mut x.y help: consider changing this to be a mutable reference | LL | fn deref_extend_mut_field1(x: &mut Own) -> &mut isize { - | ~~~~~~~~~~~~~~~ + | +++ error[E0499]: cannot borrow `*x` as mutable more than once at a time --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:78:19 @@ -82,7 +82,7 @@ LL | x.y_mut() help: consider changing this to be a mutable reference | LL | fn deref_extend_mut_method1(x: &mut Own) -> &mut isize { - | ~~~~~~~~~~~~~~~ + | +++ error[E0596]: cannot borrow `x` as mutable, as it is not declared as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref-mut.rs:129:6 diff --git a/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr index 9711dad8078..99c8fa1f932 100644 --- a/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr +++ b/tests/ui/span/borrowck-call-is-borrow-issue-12224.stderr @@ -19,7 +19,7 @@ LL | (*f)(); help: consider changing this to be a mutable reference | LL | fn test2(f: &mut F) where F: FnMut() { - | ~~~~~~ + | +++ error[E0596]: cannot borrow `f.f` as mutable, as it is behind a `&` reference --> $DIR/borrowck-call-is-borrow-issue-12224.rs:34:5 @@ -29,8 +29,8 @@ LL | f.f.call_mut(()) | help: consider changing this to be a mutable reference | -LL | fn test4(f: &mut Test<'_>) { - | ~~~~~~~~~~~~~ +LL | fn test4(f: &mut Test) { + | +++ error[E0507]: cannot move out of `f`, a captured variable in an `FnMut` closure --> $DIR/borrowck-call-is-borrow-issue-12224.rs:57:13 diff --git a/tests/ui/span/borrowck-call-method-from-mut-aliasable.stderr b/tests/ui/span/borrowck-call-method-from-mut-aliasable.stderr index 2a842f5a2a9..328197ae9f4 100644 --- a/tests/ui/span/borrowck-call-method-from-mut-aliasable.stderr +++ b/tests/ui/span/borrowck-call-method-from-mut-aliasable.stderr @@ -7,7 +7,7 @@ LL | x.h(); help: consider changing this to be a mutable reference | LL | fn b(x: &mut Foo) { - | ~~~~~~~~ + | +++ error: aborting due to previous error diff --git a/tests/ui/span/borrowck-fn-in-const-b.stderr b/tests/ui/span/borrowck-fn-in-const-b.stderr index 1df19deb12f..17fdcc622f7 100644 --- a/tests/ui/span/borrowck-fn-in-const-b.stderr +++ b/tests/ui/span/borrowck-fn-in-const-b.stderr @@ -7,7 +7,7 @@ LL | x.push(format!("this is broken")); help: consider changing this to be a mutable reference | LL | fn broken(x: &mut Vec) { - | ~~~~~~~~~~~~~~~~ + | +++ error: aborting due to previous error diff --git a/tests/ui/span/borrowck-object-mutability.stderr b/tests/ui/span/borrowck-object-mutability.stderr index b6517e0b309..805a8034c18 100644 --- a/tests/ui/span/borrowck-object-mutability.stderr +++ b/tests/ui/span/borrowck-object-mutability.stderr @@ -7,7 +7,7 @@ LL | x.borrowed_mut(); help: consider changing this to be a mutable reference | LL | fn borrowed_receiver(x: &mut dyn Foo) { - | ~~~~~~~~~~~~ + | +++ error[E0596]: cannot borrow `*x` as mutable, as `x` is not declared as mutable --> $DIR/borrowck-object-mutability.rs:18:5 diff --git a/tests/ui/span/mut-arg-hint.stderr b/tests/ui/span/mut-arg-hint.stderr index 9b82012291c..06011eac674 100644 --- a/tests/ui/span/mut-arg-hint.stderr +++ b/tests/ui/span/mut-arg-hint.stderr @@ -7,7 +7,7 @@ LL | a.push_str("bar"); help: consider changing this to be a mutable reference | LL | fn foo(mut a: &mut String) { - | ~~~~~~~~~~~ + | +++ error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/mut-arg-hint.rs:8:5 @@ -29,7 +29,7 @@ LL | a.push_str("foo"); help: consider changing this to be a mutable reference | LL | pub fn foo(mut a: &mut String) { - | ~~~~~~~~~~~ + | +++ error: aborting due to 3 previous errors diff --git a/tests/ui/suggestions/issue-68049-2.stderr b/tests/ui/suggestions/issue-68049-2.stderr index de35aa5b186..83379908159 100644 --- a/tests/ui/suggestions/issue-68049-2.stderr +++ b/tests/ui/suggestions/issue-68049-2.stderr @@ -6,8 +6,8 @@ LL | *input = self.0; | help: consider changing that to be a mutable reference | -LL | fn example(&self, input: &mut i32); // should suggest here - | ~~~~~~~~ +LL | fn example(&self, input: mut ); // should suggest here + | ~~~ error[E0594]: cannot assign to `self.0`, which is behind a `&` reference --> $DIR/issue-68049-2.rs:17:5 From 336a6569f5477d36151500bbd7c57e3bba357cec Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Wed, 19 Apr 2023 20:00:49 +1200 Subject: [PATCH 05/26] tweak "make mut" spans (No. 4) --- .../src/diagnostics/mutability_errors.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 50f9e7095f9..e842afced81 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1263,21 +1263,21 @@ fn suggest_ampmut<'tcx>( { let span = span.with_lo(span.lo() + BytePos(ws_pos as u32)).shrink_to_lo(); (true, span, " mut".to_owned()) + // if there is already a binding, we modify it to be `mut` } else if binding_exists { // shrink the span to just after the `&` in `&variable` let span = span.with_lo(span.lo() + BytePos(1)).shrink_to_lo(); (true, span, "mut ".to_owned()) + // otherwise, suggest that the user annotates the binding; we provide the + // type of the local. } else { let ty_mut = local_decl.ty.builtin_deref(true).unwrap(); assert_eq!(ty_mut.mutbl, hir::Mutability::Not); + ( - binding_exists, + false, span, - if local_decl.ty.is_ref() { - format!("&mut {}", ty_mut.ty) - } else { - format!("*mut {}", ty_mut.ty) - }, + format!("{}mut {}", if local_decl.ty.is_ref() {"&"} else {"*"}, ty_mut.ty) ) } } From 87a1b3840ecfebdcd22313ed37f0609732d8cf83 Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Thu, 20 Apr 2023 18:58:43 +1200 Subject: [PATCH 06/26] tweak spans for `ref mut` suggestion --- .../src/diagnostics/mutability_errors.rs | 16 +++++++++------- tests/ui/nll/issue-51244.stderr | 2 +- .../borrowck-move-ref-pattern.stderr | 4 ++-- tests/ui/suggestions/suggest-ref-mut.rs | 3 --- tests/ui/suggestions/suggest-ref-mut.stderr | 12 ++++++------ 5 files changed, 18 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index e842afced81..0a89eb07245 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -559,9 +559,9 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { binding_mode: ty::BindingMode::BindByReference(_), .. })) => { - let pattern_span = local_decl.source_info.span; + let pattern_span: Span = local_decl.source_info.span; suggest_ref_mut(self.infcx.tcx, pattern_span) - .map(|replacement| (true, pattern_span, replacement)) + .map(|span| (true, span, "mut ".to_owned())) } _ => unreachable!(), @@ -1316,11 +1316,13 @@ fn get_mut_span_in_struct_field<'tcx>( } /// If possible, suggest replacing `ref` with `ref mut`. -fn suggest_ref_mut(tcx: TyCtxt<'_>, binding_span: Span) -> Option { - let hi_src = tcx.sess.source_map().span_to_snippet(binding_span).ok()?; - if hi_src.starts_with("ref") && hi_src["ref".len()..].starts_with(rustc_lexer::is_whitespace) { - let replacement = format!("ref mut{}", &hi_src["ref".len()..]); - Some(replacement) +fn suggest_ref_mut(tcx: TyCtxt<'_>, span: Span) -> Option { + let pattern_str = tcx.sess.source_map().span_to_snippet(span).ok()?; + if pattern_str.starts_with("ref") + && pattern_str["ref".len()..].starts_with(rustc_lexer::is_whitespace) + { + let span = span.with_lo(span.lo() + BytePos(4)).shrink_to_lo(); + Some(span) } else { None } diff --git a/tests/ui/nll/issue-51244.stderr b/tests/ui/nll/issue-51244.stderr index 03d8acc8188..8ccb5809e39 100644 --- a/tests/ui/nll/issue-51244.stderr +++ b/tests/ui/nll/issue-51244.stderr @@ -7,7 +7,7 @@ LL | *my_ref = 0; help: consider changing this to be a mutable reference | LL | let ref mut my_ref @ _ = 0; - | ~~~~~~~~~~~~~~ + | +++ error: aborting due to previous error diff --git a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr index c7c7c074f7c..a033cc0655e 100644 --- a/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr +++ b/tests/ui/pattern/move-ref-patterns/borrowck-move-ref-pattern.stderr @@ -112,7 +112,7 @@ LL | *_x0 = U; help: consider changing this to be a mutable reference | LL | let (ref mut _x0, _x1, ref _x2, ..) = tup; - | ~~~~~~~~~~~ + | +++ error[E0594]: cannot assign to `*_x2`, which is behind a `&` reference --> $DIR/borrowck-move-ref-pattern.rs:27:5 @@ -123,7 +123,7 @@ LL | *_x2 = U; help: consider changing this to be a mutable reference | LL | let (ref _x0, _x1, ref mut _x2, ..) = tup; - | ~~~~~~~~~~~ + | +++ error[E0382]: use of moved value: `tup.1` --> $DIR/borrowck-move-ref-pattern.rs:28:10 diff --git a/tests/ui/suggestions/suggest-ref-mut.rs b/tests/ui/suggestions/suggest-ref-mut.rs index d04113ffccc..b40439b8e37 100644 --- a/tests/ui/suggestions/suggest-ref-mut.rs +++ b/tests/ui/suggestions/suggest-ref-mut.rs @@ -12,12 +12,10 @@ impl X { fn main() { let ref foo = 16; //~^ HELP - //~| SUGGESTION ref mut foo *foo = 32; //~^ ERROR if let Some(ref bar) = Some(16) { //~^ HELP - //~| SUGGESTION ref mut bar *bar = 32; //~^ ERROR } @@ -25,6 +23,5 @@ fn main() { ref quo => { *quo = 32; }, //~^ ERROR //~| HELP - //~| SUGGESTION ref mut quo } } diff --git a/tests/ui/suggestions/suggest-ref-mut.stderr b/tests/ui/suggestions/suggest-ref-mut.stderr index 7973759bf5e..cc00022ab8e 100644 --- a/tests/ui/suggestions/suggest-ref-mut.stderr +++ b/tests/ui/suggestions/suggest-ref-mut.stderr @@ -10,7 +10,7 @@ LL | fn zap(&mut self) { | ~~~~~~~~~ error[E0594]: cannot assign to `*foo`, which is behind a `&` reference - --> $DIR/suggest-ref-mut.rs:16:5 + --> $DIR/suggest-ref-mut.rs:15:5 | LL | *foo = 32; | ^^^^^^^^^ `foo` is a `&` reference, so the data it refers to cannot be written @@ -18,10 +18,10 @@ LL | *foo = 32; help: consider changing this to be a mutable reference | LL | let ref mut foo = 16; - | ~~~~~~~~~~~ + | +++ error[E0594]: cannot assign to `*bar`, which is behind a `&` reference - --> $DIR/suggest-ref-mut.rs:21:9 + --> $DIR/suggest-ref-mut.rs:19:9 | LL | *bar = 32; | ^^^^^^^^^ `bar` is a `&` reference, so the data it refers to cannot be written @@ -29,10 +29,10 @@ LL | *bar = 32; help: consider changing this to be a mutable reference | LL | if let Some(ref mut bar) = Some(16) { - | ~~~~~~~~~~~ + | +++ error[E0594]: cannot assign to `*quo`, which is behind a `&` reference - --> $DIR/suggest-ref-mut.rs:25:22 + --> $DIR/suggest-ref-mut.rs:23:22 | LL | ref quo => { *quo = 32; }, | ^^^^^^^^^ `quo` is a `&` reference, so the data it refers to cannot be written @@ -40,7 +40,7 @@ LL | ref quo => { *quo = 32; }, help: consider changing this to be a mutable reference | LL | ref mut quo => { *quo = 32; }, - | ~~~~~~~~~~~ + | +++ error: aborting due to 4 previous errors From d2608dfabb3a353fd2ab25f8bb1abf04b497af3b Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Fri, 21 Apr 2023 13:29:15 +1200 Subject: [PATCH 07/26] implement review comment Co-authored-by: Esteban Kuber --- compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index 0a89eb07245..a98a07a74e5 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1268,9 +1268,9 @@ fn suggest_ampmut<'tcx>( // shrink the span to just after the `&` in `&variable` let span = span.with_lo(span.lo() + BytePos(1)).shrink_to_lo(); (true, span, "mut ".to_owned()) - // otherwise, suggest that the user annotates the binding; we provide the - // type of the local. } else { + // otherwise, suggest that the user annotates the binding; we provide the + // type of the local. let ty_mut = local_decl.ty.builtin_deref(true).unwrap(); assert_eq!(ty_mut.mutbl, hir::Mutability::Not); From 3e64e986fe1cbaa3679cd228a6900304ebf81018 Mon Sep 17 00:00:00 2001 From: Ezra Shaw Date: Fri, 21 Apr 2023 23:49:05 +1200 Subject: [PATCH 08/26] fix trait definition spans in "make mut" suggestion --- .../src/diagnostics/mutability_errors.rs | 393 +++++++++--------- tests/ui/suggestions/issue-68049-2.stderr | 8 +- 2 files changed, 201 insertions(+), 200 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index a98a07a74e5..6286033e067 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1,4 +1,4 @@ -use rustc_errors::{Applicability, Diagnostic}; +use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed}; use rustc_hir as hir; use rustc_hir::intravisit::Visitor; use rustc_hir::Node; @@ -478,179 +478,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { match self.local_names[local] { Some(name) if !local_decl.from_compiler_desugaring() => { - let label = match *local_decl.local_info() { - LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => { - let (span, suggestion) = - suggest_ampmut_self(self.infcx.tcx, local_decl); - Some((true, span, suggestion)) - } - - LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByValue(_), - opt_ty_info, - .. - })) => { - // check if the RHS is from desugaring - let opt_assignment_rhs_span = - self.body.find_assignments(local).first().map(|&location| { - if let Some(mir::Statement { - source_info: _, - kind: - mir::StatementKind::Assign(box ( - _, - mir::Rvalue::Use(mir::Operand::Copy(place)), - )), - }) = self.body[location.block] - .statements - .get(location.statement_index) - { - self.body.local_decls[place.local].source_info.span - } else { - self.body.source_info(location).span - } - }); - match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) { - // on for loops, RHS points to the iterator part - Some(DesugaringKind::ForLoop) => { - self.suggest_similar_mut_method_for_for_loop(&mut err); - err.span_label(opt_assignment_rhs_span.unwrap(), format!( - "this iterator yields `{pointer_sigil}` {pointer_desc}s", - )); - None - } - // don't create labels for compiler-generated spans - Some(_) => None, - None => { - let label = if name != kw::SelfLower { - suggest_ampmut( - self.infcx.tcx, - local_decl, - opt_assignment_rhs_span, - opt_ty_info, - ) - } else { - match local_decl.local_info() { - LocalInfo::User(mir::BindingForm::Var( - mir::VarBindingForm { - opt_ty_info: None, .. - }, - )) => { - let (span, sugg) = suggest_ampmut_self( - self.infcx.tcx, - local_decl, - ); - (true, span, sugg) - } - // explicit self (eg `self: &'a Self`) - _ => suggest_ampmut( - self.infcx.tcx, - local_decl, - opt_assignment_rhs_span, - opt_ty_info, - ), - } - }; - Some(label) - } - } - } - - LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm { - binding_mode: ty::BindingMode::BindByReference(_), - .. - })) => { - let pattern_span: Span = local_decl.source_info.span; - suggest_ref_mut(self.infcx.tcx, pattern_span) - .map(|span| (true, span, "mut ".to_owned())) - } - - _ => unreachable!(), - }; - - match label { - Some((true, err_help_span, suggested_code)) => { - let (is_trait_sig, local_trait) = self.is_error_in_trait(local); - if !is_trait_sig { - err.span_suggestion_verbose( - 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_verbose( - x, - format!( - "consider changing that to be a mutable {pointer_desc}" - ), - suggested_code, - Applicability::MachineApplicable, - ); - } - } - Some((false, err_label_span, message)) => { - struct BindingFinder { - span: Span, - hir_id: Option, - } - - impl<'tcx> Visitor<'tcx> for BindingFinder { - fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) { - if let hir::StmtKind::Local(local) = s.kind { - if local.pat.span == self.span { - self.hir_id = Some(local.hir_id); - } - } - hir::intravisit::walk_stmt(self, s); - } - } - let hir_map = self.infcx.tcx.hir(); - let def_id = self.body.source.def_id(); - let hir_id = hir_map.local_def_id_to_hir_id(def_id.expect_local()); - let node = hir_map.find(hir_id); - let hir_id = if let Some(hir::Node::Item(item)) = node - && let hir::ItemKind::Fn(.., body_id) = item.kind - { - let body = hir_map.body(body_id); - let mut v = BindingFinder { - span: err_label_span, - hir_id: None, - }; - v.visit_body(body); - v.hir_id - } else { - None - }; - if let Some(hir_id) = hir_id - && let Some(hir::Node::Local(local)) = hir_map.find(hir_id) - { - let (changing, span, sugg) = match local.ty { - Some(ty) => ("changing", ty.span, message), - None => ( - "specifying", - local.pat.span.shrink_to_hi(), - format!(": {message}"), - ), - }; - err.span_suggestion_verbose( - span, - format!("consider {changing} this binding's type"), - sugg, - Applicability::HasPlaceholders, - ); - } else { - err.span_label( - err_label_span, - format!( - "consider changing this binding's type to be: `{message}`" - ), - ); - } - } - None => {} - } err.span_label( span, format!( @@ -658,6 +485,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { so the data it refers to cannot be {acted_on}", ), ); + + self.suggest_make_local_mut(&mut err, local, name); } _ => { err.span_label( @@ -1131,6 +960,184 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } } + + fn suggest_make_local_mut( + &self, + err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>, + local: Local, + name: Symbol, + ) { + let local_decl = &self.body.local_decls[local]; + + let (pointer_sigil, pointer_desc) = + if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") }; + + let (is_trait_sig, local_trait) = self.is_error_in_trait(local); + if is_trait_sig && local_trait.is_none() { + return; + } + + let decl_span = match local_trait { + Some(span) => span, + None => local_decl.source_info.span, + }; + + let label = match *local_decl.local_info() { + LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => { + let suggestion = suggest_ampmut_self(self.infcx.tcx, decl_span); + Some((true, decl_span, suggestion)) + } + + LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByValue(_), + opt_ty_info, + .. + })) => { + // check if the RHS is from desugaring + let opt_assignment_rhs_span = + self.body.find_assignments(local).first().map(|&location| { + if let Some(mir::Statement { + source_info: _, + kind: + mir::StatementKind::Assign(box ( + _, + mir::Rvalue::Use(mir::Operand::Copy(place)), + )), + }) = self.body[location.block].statements.get(location.statement_index) + { + self.body.local_decls[place.local].source_info.span + } else { + self.body.source_info(location).span + } + }); + match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) { + // on for loops, RHS points to the iterator part + Some(DesugaringKind::ForLoop) => { + self.suggest_similar_mut_method_for_for_loop(err); + err.span_label( + opt_assignment_rhs_span.unwrap(), + format!("this iterator yields `{pointer_sigil}` {pointer_desc}s",), + ); + None + } + // don't create labels for compiler-generated spans + Some(_) => None, + None => { + let label = if name != kw::SelfLower { + suggest_ampmut( + self.infcx.tcx, + local_decl.ty, + decl_span, + opt_assignment_rhs_span, + opt_ty_info, + ) + } else { + match local_decl.local_info() { + LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm { + opt_ty_info: None, + .. + })) => { + let sugg = suggest_ampmut_self(self.infcx.tcx, decl_span); + (true, decl_span, sugg) + } + // explicit self (eg `self: &'a Self`) + _ => suggest_ampmut( + self.infcx.tcx, + local_decl.ty, + decl_span, + opt_assignment_rhs_span, + opt_ty_info, + ), + } + }; + Some(label) + } + } + } + + LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm { + binding_mode: ty::BindingMode::BindByReference(_), + .. + })) => { + let pattern_span: Span = local_decl.source_info.span; + suggest_ref_mut(self.infcx.tcx, pattern_span) + .map(|span| (true, span, "mut ".to_owned())) + } + + _ => unreachable!(), + }; + + match label { + Some((true, err_help_span, suggested_code)) => { + err.span_suggestion_verbose( + err_help_span, + format!("consider changing this to be a mutable {pointer_desc}"), + suggested_code, + Applicability::MachineApplicable, + ); + } + Some((false, err_label_span, message)) => { + struct BindingFinder { + span: Span, + hir_id: Option, + } + + impl<'tcx> Visitor<'tcx> for BindingFinder { + fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) { + if let hir::StmtKind::Local(local) = s.kind { + if local.pat.span == self.span { + self.hir_id = Some(local.hir_id); + } + } + hir::intravisit::walk_stmt(self, s); + } + } + let hir_map = self.infcx.tcx.hir(); + let def_id = self.body.source.def_id(); + let hir_id = hir_map.local_def_id_to_hir_id(def_id.expect_local()); + let node = hir_map.find(hir_id); + let hir_id = if let Some(hir::Node::Item(item)) = node + && let hir::ItemKind::Fn(.., body_id) = item.kind + { + let body = hir_map.body(body_id); + let mut v = BindingFinder { + span: err_label_span, + hir_id: None, + }; + v.visit_body(body); + v.hir_id + } else { + None + }; + if let Some(hir_id) = hir_id + && let Some(hir::Node::Local(local)) = hir_map.find(hir_id) + { + let (changing, span, sugg) = match local.ty { + Some(ty) => ("changing", ty.span, message), + None => ( + "specifying", + local.pat.span.shrink_to_hi(), + format!(": {message}"), + ), + }; + err.span_suggestion_verbose( + span, + format!("consider {changing} this binding's type"), + sugg, + Applicability::HasPlaceholders, + ); + } else { + err.span_label( + err_label_span, + format!( + "consider changing this binding's type to be: `{message}`" + ), + ); + } + } + None => {} + } + } } pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option) -> bool { @@ -1160,25 +1167,18 @@ pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option< } } -fn suggest_ampmut_self<'tcx>( - tcx: TyCtxt<'tcx>, - local_decl: &mir::LocalDecl<'tcx>, -) -> (Span, String) { - let sp = local_decl.source_info.span; - ( - sp, - match tcx.sess.source_map().span_to_snippet(sp) { - Ok(snippet) => { - let lt_pos = snippet.find('\''); - if let Some(lt_pos) = lt_pos { - format!("&{}mut self", &snippet[lt_pos..snippet.len() - 4]) - } else { - "&mut self".to_string() - } +fn suggest_ampmut_self<'tcx>(tcx: TyCtxt<'tcx>, span: Span) -> String { + match tcx.sess.source_map().span_to_snippet(span) { + Ok(snippet) => { + let lt_pos = snippet.find('\''); + if let Some(lt_pos) = lt_pos { + format!("&{}mut self", &snippet[lt_pos..snippet.len() - 4]) + } else { + "&mut self".to_string() } - _ => "&mut self".to_string(), - }, - ) + } + _ => "&mut self".to_string(), + } } // When we want to suggest a user change a local variable to be a `&mut`, there @@ -1198,7 +1198,8 @@ fn suggest_ampmut_self<'tcx>( // by trying (3.), then (2.) and finally falling back on (1.). fn suggest_ampmut<'tcx>( tcx: TyCtxt<'tcx>, - local_decl: &mir::LocalDecl<'tcx>, + decl_ty: Ty<'tcx>, + decl_span: Span, opt_assignment_rhs_span: Option, opt_ty_info: Option, ) -> (bool, Span, String) { @@ -1250,7 +1251,7 @@ fn suggest_ampmut<'tcx>( // otherwise, we'll suggest *adding* an annotated type, we'll suggest // the RHS's type for that. // this is `Applicability::HasPlaceholders`. - None => (false, local_decl.source_info.span), + None => (false, decl_span), }; // if the binding already exists and is a reference with a explicit @@ -1271,13 +1272,13 @@ fn suggest_ampmut<'tcx>( } else { // otherwise, suggest that the user annotates the binding; we provide the // type of the local. - let ty_mut = local_decl.ty.builtin_deref(true).unwrap(); + let ty_mut = decl_ty.builtin_deref(true).unwrap(); assert_eq!(ty_mut.mutbl, hir::Mutability::Not); ( false, span, - format!("{}mut {}", if local_decl.ty.is_ref() {"&"} else {"*"}, ty_mut.ty) + format!("{}mut {}", if decl_ty.is_ref() {"&"} else {"*"}, ty_mut.ty) ) } } diff --git a/tests/ui/suggestions/issue-68049-2.stderr b/tests/ui/suggestions/issue-68049-2.stderr index 83379908159..6f3c78443f8 100644 --- a/tests/ui/suggestions/issue-68049-2.stderr +++ b/tests/ui/suggestions/issue-68049-2.stderr @@ -4,10 +4,10 @@ error[E0594]: cannot assign to `*input`, which is behind a `&` reference LL | *input = self.0; | ^^^^^^^^^^^^^^^ `input` is a `&` reference, so the data it refers to cannot be written | -help: consider changing that to be a mutable reference +help: consider changing this to be a mutable reference | -LL | fn example(&self, input: mut ); // should suggest here - | ~~~ +LL | fn example(&self, input: &mut i32) { // should not suggest here + | +++ error[E0594]: cannot assign to `self.0`, which is behind a `&` reference --> $DIR/issue-68049-2.rs:17:5 @@ -15,7 +15,7 @@ error[E0594]: cannot assign to `self.0`, which is behind a `&` reference LL | self.0 += *input; | ^^^^^^^^^^^^^^^^ `self` is a `&` reference, so the data it refers to cannot be written | -help: consider changing that to be a mutable reference +help: consider changing this to be a mutable reference | LL | fn example(&mut self, input: &i32); // should suggest here | ~~~~~~~~~ From bd928a0b5e144b0fafb2f4659a83aa362de7e3c7 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 5 May 2023 12:54:58 +0100 Subject: [PATCH 09/26] Disallow (min) specialization imps with no items Such implementations are usually mistakes and are not used in the compiler or standard library (after this commit) so forbid them with `min_specialization`. --- .../rustc_data_structures/src/owned_slice.rs | 2 ++ compiler/rustc_hir_analysis/messages.ftl | 3 +++ compiler/rustc_hir_analysis/src/errors.rs | 9 +++++++ .../src/impl_wf_check/min_specialization.rs | 15 +++++++++++- compiler/rustc_middle/src/mir/mod.rs | 2 -- ...fault-bound-non-const-specialized-bound.rs | 24 ++++++++++++++----- ...t-bound-non-const-specialized-bound.stderr | 4 ++-- .../issue-95186-specialize-on-tilde-const.rs | 24 ++++++++++++++----- ...87-same-trait-bound-different-constness.rs | 24 ++++++++++++++----- .../min_specialization/specialize_nothing.rs | 14 +++++++++++ .../specialize_nothing.stderr | 14 +++++++++++ 11 files changed, 112 insertions(+), 23 deletions(-) create mode 100644 tests/ui/specialization/min_specialization/specialize_nothing.rs create mode 100644 tests/ui/specialization/min_specialization/specialize_nothing.stderr diff --git a/compiler/rustc_data_structures/src/owned_slice.rs b/compiler/rustc_data_structures/src/owned_slice.rs index 048401f66c2..311a42aa42a 100644 --- a/compiler/rustc_data_structures/src/owned_slice.rs +++ b/compiler/rustc_data_structures/src/owned_slice.rs @@ -109,9 +109,11 @@ impl Borrow<[u8]> for OwnedSlice { } // Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box)`, which is `Send` +#[cfg(parallel_compiler)] unsafe impl Send for OwnedSlice {} // Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box)`, which is `Sync` +#[cfg(parallel_compiler)] unsafe impl Sync for OwnedSlice {} #[cfg(test)] diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl index eaa75bde6c6..c130eaae755 100644 --- a/compiler/rustc_hir_analysis/messages.ftl +++ b/compiler/rustc_hir_analysis/messages.ftl @@ -275,6 +275,9 @@ hir_analysis_specialization_trait = implementing `rustc_specialization_trait` tr hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present .label = `for<...>` is here +hir_analysis_empty_specialization = specialization impl does not specialize any associated items + .note = impl is a specialization of this impl + hir_analysis_const_specialize = cannot specialize on const impl with non-const impl hir_analysis_static_specialize = cannot specialize on `'static` lifetime diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs index c0ee777722e..32e91af2608 100644 --- a/compiler/rustc_hir_analysis/src/errors.rs +++ b/compiler/rustc_hir_analysis/src/errors.rs @@ -803,6 +803,15 @@ pub(crate) struct ClosureImplicitHrtb { pub for_sp: Span, } +#[derive(Diagnostic)] +#[diag(hir_analysis_empty_specialization)] +pub(crate) struct EmptySpecialization { + #[primary_span] + pub span: Span, + #[note] + pub base_impl_span: Span, +} + #[derive(Diagnostic)] #[diag(hir_analysis_const_specialize)] pub(crate) struct ConstSpecialize { diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 5cca2dacb5c..4f0df5c5677 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -100,12 +100,19 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Opti // Implementing a normal trait isn't a specialization. return None; } + if trait_def.is_marker { + // Overlapping marker implementations are not really specializations. + return None; + } Some(impl2_node) } /// Check that `impl1` is a sound specialization #[instrument(level = "debug", skip(tcx))] fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node) { + let span = tcx.def_span(impl1_def_id); + check_has_items(tcx, impl1_def_id, impl2_node, span); + if let Some((impl1_substs, impl2_substs)) = get_impl_substs(tcx, impl1_def_id, impl2_node) { let impl2_def_id = impl2_node.def_id(); debug!(?impl2_def_id, ?impl2_substs); @@ -116,7 +123,6 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node unconstrained_parent_impl_substs(tcx, impl2_def_id, impl2_substs) }; - let span = tcx.def_span(impl1_def_id); check_constness(tcx, impl1_def_id, impl2_node, span); check_static_lifetimes(tcx, &parent_substs, span); check_duplicate_params(tcx, impl1_substs, &parent_substs, span); @@ -124,6 +130,13 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node } } +fn check_has_items(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) { + if let Node::Impl(impl2_id) = impl2_node && tcx.associated_item_def_ids(impl1_def_id).is_empty() { + let base_impl_span = tcx.def_span(impl2_id); + tcx.sess.emit_err(errors::EmptySpecialization { span, base_impl_span }); + } +} + /// Check that the specializing impl `impl1` is at least as const as the base /// impl `impl2` fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) { diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 858a3d266ea..f2841182a1a 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -2728,8 +2728,6 @@ pub struct UserTypeProjection { pub projs: Vec, } -impl Copy for ProjectionKind {} - impl UserTypeProjection { pub(crate) fn index(mut self) -> Self { self.projs.push(ProjectionElem::Index(())); diff --git a/tests/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs b/tests/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs index 3ac90992486..f31123f16f1 100644 --- a/tests/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs +++ b/tests/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.rs @@ -12,7 +12,9 @@ trait Specialize {} trait Foo {} #[const_trait] -trait Bar {} +trait Bar { + fn bar(); +} // bgr360: I was only able to exercise the code path that raises the // "missing ~const qualifier" error by making this base impl non-const, even @@ -21,26 +23,36 @@ trait Bar {} impl Bar for T where T: ~const Foo, -{} +{ + default fn bar() {} +} impl Bar for T where T: Foo, //~ ERROR missing `~const` qualifier T: Specialize, -{} +{ + fn bar() {} +} #[const_trait] -trait Baz {} +trait Baz { + fn baz(); +} impl const Baz for T where T: ~const Foo, -{} +{ + default fn baz() {} +} impl const Baz for T //~ ERROR conflicting implementations of trait `Baz` where T: Foo, T: Specialize, -{} +{ + fn baz() {} +} fn main() {} diff --git a/tests/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr b/tests/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr index 4aea1979421..057cf4aea8a 100644 --- a/tests/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr +++ b/tests/ui/rfc-2632-const-trait-impl/specialization/const-default-bound-non-const-specialized-bound.stderr @@ -1,11 +1,11 @@ error: missing `~const` qualifier for specialization - --> $DIR/const-default-bound-non-const-specialized-bound.rs:28:8 + --> $DIR/const-default-bound-non-const-specialized-bound.rs:32:8 | LL | T: Foo, | ^^^ error[E0119]: conflicting implementations of trait `Baz` - --> $DIR/const-default-bound-non-const-specialized-bound.rs:40:1 + --> $DIR/const-default-bound-non-const-specialized-bound.rs:50:1 | LL | impl const Baz for T | ----------------------- first implementation here diff --git a/tests/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs b/tests/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs index 9c2c2cf1610..92d8be6bb16 100644 --- a/tests/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs +++ b/tests/ui/rfc-2632-const-trait-impl/specialization/issue-95186-specialize-on-tilde-const.rs @@ -11,27 +11,39 @@ trait Specialize {} #[const_trait] -trait Foo {} +trait Foo { + fn foo(); +} -impl const Foo for T {} +impl const Foo for T { + default fn foo() {} +} impl const Foo for T where T: ~const Specialize, -{} +{ + fn foo() {} +} #[const_trait] -trait Bar {} +trait Bar { + fn bar() {} +} impl const Bar for T where T: ~const Foo, -{} +{ + default fn bar() {} +} impl const Bar for T where T: ~const Foo, T: ~const Specialize, -{} +{ + fn bar() {} +} fn main() {} diff --git a/tests/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs b/tests/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs index 1e6b1c6513b..51bfaf73b57 100644 --- a/tests/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs +++ b/tests/ui/rfc-2632-const-trait-impl/specialization/issue-95187-same-trait-bound-different-constness.rs @@ -15,31 +15,43 @@ trait Specialize {} trait Foo {} #[const_trait] -trait Bar {} +trait Bar { + fn bar(); +} impl Bar for T where T: Foo, -{} +{ + default fn bar() {} +} impl const Bar for T where T: ~const Foo, T: Specialize, -{} +{ + fn bar() {} +} #[const_trait] -trait Baz {} +trait Baz { + fn baz(); +} impl const Baz for T where T: Foo, -{} +{ + default fn baz() {} +} impl const Baz for T where T: ~const Foo, T: Specialize, -{} +{ + fn baz() {} +} fn main() {} diff --git a/tests/ui/specialization/min_specialization/specialize_nothing.rs b/tests/ui/specialization/min_specialization/specialize_nothing.rs new file mode 100644 index 00000000000..ef92254d465 --- /dev/null +++ b/tests/ui/specialization/min_specialization/specialize_nothing.rs @@ -0,0 +1,14 @@ +#![feature(min_specialization)] + +trait Special { + fn be_special(); +} + +impl Special for T { + fn be_special() {} +} + +impl Special for usize {} +//~^ ERROR specialization impl does not specialize any associated items + +fn main() {} diff --git a/tests/ui/specialization/min_specialization/specialize_nothing.stderr b/tests/ui/specialization/min_specialization/specialize_nothing.stderr new file mode 100644 index 00000000000..65f73781cae --- /dev/null +++ b/tests/ui/specialization/min_specialization/specialize_nothing.stderr @@ -0,0 +1,14 @@ +error: specialization impl does not specialize any associated items + --> $DIR/specialize_nothing.rs:11:1 + | +LL | impl Special for usize {} + | ^^^^^^^^^^^^^^^^^^^^^^ + | +note: impl is a specialization of this impl + --> $DIR/specialize_nothing.rs:7:1 + | +LL | impl Special for T { + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + From fafe9e71d5c949c41a5a562e44cc40d72c5f7244 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 5 May 2023 15:50:17 +0100 Subject: [PATCH 10/26] Normalize consistently for specializations --- .../src/traits/specialize/mod.rs | 39 +++++++++++-------- .../specialize-associated-type.rs | 37 ++++++++++++++++++ .../specialize_on_type_error.rs | 33 ++++++++++++++++ .../specialize_on_type_error.stderr | 12 ++++++ 4 files changed, 104 insertions(+), 17 deletions(-) create mode 100644 tests/ui/specialization/min_specialization/specialize-associated-type.rs create mode 100644 tests/ui/specialization/min_specialization/specialize_on_type_error.rs create mode 100644 tests/ui/specialization/min_specialization/specialize_on_type_error.stderr diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 233d35aed38..8bbebadb22a 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -99,14 +99,13 @@ pub fn translate_substs<'tcx>( return source_substs; } - fulfill_implication(infcx, param_env, source_trait_ref, target_impl).unwrap_or_else( - |()| { + fulfill_implication(infcx, param_env, source_trait_ref, source_impl, target_impl) + .unwrap_or_else(|()| { bug!( "When translating substitutions from {source_impl:?} to {target_impl:?}, \ the expected specialization failed to hold" ) - }, - ) + }) } specialization_graph::Node::Trait(..) => source_trait_ref.substs, }; @@ -153,20 +152,9 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, // Create an infcx, taking the predicates of impl1 as assumptions: let infcx = tcx.infer_ctxt().build(); - let impl1_trait_ref = - match traits::fully_normalize(&infcx, ObligationCause::dummy(), penv, impl1_trait_ref) { - Ok(impl1_trait_ref) => impl1_trait_ref, - Err(_errors) => { - tcx.sess.delay_span_bug( - tcx.def_span(impl1_def_id), - format!("failed to fully normalize {impl1_trait_ref}"), - ); - impl1_trait_ref - } - }; // Attempt to prove that impl2 applies, given all of the above. - fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok() + fulfill_implication(&infcx, penv, impl1_trait_ref, impl1_def_id, impl2_def_id).is_ok() } /// Attempt to fulfill all obligations of `target_impl` after unification with @@ -178,6 +166,7 @@ fn fulfill_implication<'tcx>( infcx: &InferCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, source_trait_ref: ty::TraitRef<'tcx>, + source_impl: DefId, target_impl: DefId, ) -> Result, ()> { debug!( @@ -185,6 +174,22 @@ fn fulfill_implication<'tcx>( param_env, source_trait_ref, target_impl ); + let source_trait_ref = match traits::fully_normalize( + &infcx, + ObligationCause::dummy(), + param_env, + source_trait_ref, + ) { + Ok(source_trait_ref) => source_trait_ref, + Err(_errors) => { + infcx.tcx.sess.delay_span_bug( + infcx.tcx.def_span(source_impl), + format!("failed to fully normalize {source_trait_ref}"), + ); + source_trait_ref + } + }; + let source_trait = ImplSubject::Trait(source_trait_ref); let selcx = &mut SelectionContext::new(&infcx); @@ -194,7 +199,7 @@ fn fulfill_implication<'tcx>( // do the impls unify? If not, no specialization. let Ok(InferOk { obligations: more_obligations, .. }) = - infcx.at(&ObligationCause::dummy(), param_env, ).eq(DefineOpaqueTypes::No,source_trait, target_trait) + infcx.at(&ObligationCause::dummy(), param_env).eq(DefineOpaqueTypes::No, source_trait, target_trait) else { debug!( "fulfill_implication: {:?} does not unify with {:?}", diff --git a/tests/ui/specialization/min_specialization/specialize-associated-type.rs b/tests/ui/specialization/min_specialization/specialize-associated-type.rs new file mode 100644 index 00000000000..c4960b0c28e --- /dev/null +++ b/tests/ui/specialization/min_specialization/specialize-associated-type.rs @@ -0,0 +1,37 @@ +// Another regression test for #109815. + +// check-pass + +#![feature(min_specialization)] +#![feature(rustc_attrs)] + +#[rustc_specialization_trait] +trait X {} +trait Z { + type Assoc: X; +} +struct A(T); + +impl X for () {} + +impl Z for A { + type Assoc = (); +} + +trait MyFrom { + fn from(other: T) -> Self; +} + +impl MyFrom<()> for T { + default fn from(other: ()) -> T { + panic!(); + } +} + +impl MyFrom< as Z>::Assoc> for T { + fn from(other: ()) -> T { + panic!(); + } +} + +fn main() {} diff --git a/tests/ui/specialization/min_specialization/specialize_on_type_error.rs b/tests/ui/specialization/min_specialization/specialize_on_type_error.rs new file mode 100644 index 00000000000..24e92a0abc3 --- /dev/null +++ b/tests/ui/specialization/min_specialization/specialize_on_type_error.rs @@ -0,0 +1,33 @@ +// A regression test for #109815. + +#![feature(min_specialization)] +#![feature(rustc_attrs)] + +#[rustc_specialization_trait] +trait X {} +trait Y: X {} +trait Z { + type Assoc: Y; +} +struct A(T); + +impl Z for A {} +//~^ ERROR not all trait items implemented + +trait MyFrom { + fn from(other: T) -> Self; +} + +impl MyFrom for T { + default fn from(other: T) -> T { + other + } +} + +impl MyFrom< as Z>::Assoc> for T { + fn from(other: as Z>::Assoc) -> T { + other + } +} + +fn main() {} diff --git a/tests/ui/specialization/min_specialization/specialize_on_type_error.stderr b/tests/ui/specialization/min_specialization/specialize_on_type_error.stderr new file mode 100644 index 00000000000..cc12302bd8c --- /dev/null +++ b/tests/ui/specialization/min_specialization/specialize_on_type_error.stderr @@ -0,0 +1,12 @@ +error[E0046]: not all trait items implemented, missing: `Assoc` + --> $DIR/specialize_on_type_error.rs:14:1 + | +LL | type Assoc: Y; + | ------------- `Assoc` from trait +... +LL | impl Z for A {} + | ^^^^^^^^^^^^^^^^^^^^^ missing `Assoc` in implementation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0046`. From 68a5bb4de153565d93e084904154439777ad5c31 Mon Sep 17 00:00:00 2001 From: Charisee Date: Fri, 5 May 2023 18:32:20 +0000 Subject: [PATCH 11/26] Add GNU Property Note --- .../rustc_codegen_ssa/src/back/metadata.rs | 26 +++++++++++-------- .../branch-protection-check-IBT/Makefile | 15 +++++++++++ .../branch-protection-check-IBT/main.rs | 3 +++ 3 files changed, 33 insertions(+), 11 deletions(-) create mode 100644 tests/run-make/branch-protection-check-IBT/Makefile create mode 100644 tests/run-make/branch-protection-check-IBT/main.rs diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index baf674cf9eb..d4515a794ee 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -98,6 +98,7 @@ fn add_gnu_property_note( file: &mut write::Object<'static>, architecture: Architecture, binary_format: BinaryFormat, + endianness: Endianness, ) { // check bti protection if binary_format != BinaryFormat::Elf @@ -115,12 +116,12 @@ fn add_gnu_property_note( let n_namsz: u32 = 4; // Size of the n_name field let n_descsz: u32 = 16; // Size of the n_desc field let n_type: u32 = NT_GNU_PROPERTY_TYPE_0; // Type of note descriptor - let values = [n_namsz, n_descsz, n_type]; - values.map(|v| data.extend_from_slice(&(v.to_le_bytes()))); - data.push(b'G'); // Owner of the program property note - data.push(b'N'); - data.push(b'U'); - data.push(0); + let header_values = [n_namsz, n_descsz, n_type]; + match endianness { + Endianness::Little => header_values.map(|v| data.extend_from_slice(&(v.to_le_bytes()))), + Endianness::Big => header_values.map(|v| data.extend_from_slice(&(v.to_be_bytes()))), + }; + data.extend_from_slice(b"GNU\0"); // Owner of the program property note let pr_type: u32 = match architecture { Architecture::X86_64 => 0xc0000002, Architecture::Aarch64 => 0xc0000000, @@ -128,10 +129,13 @@ fn add_gnu_property_note( }; let pr_datasz: u32 = 4; //size of the pr_data field let pr_data: u32 = 3; //program property descriptor - let pr_padding: u32 = 3; - let values = [pr_type, pr_datasz, pr_data, pr_padding]; - values.map(|v| data.extend_from_slice(&(v.to_le_bytes()))); - file.append_section_data(section, &data, 4); + let pr_padding: u32 = 0; + let property_values = [pr_type, pr_datasz, pr_data, pr_padding]; + match endianness { + Endianness::Little => property_values.map(|v| data.extend_from_slice(&(v.to_le_bytes()))), + Endianness::Big => property_values.map(|v| data.extend_from_slice(&(v.to_be_bytes()))), + }; + file.append_section_data(section, &data, 8); } pub(crate) fn create_object_file(sess: &Session) -> Option> { @@ -246,7 +250,7 @@ pub(crate) fn create_object_file(sess: &Session) -> Option elf::ELFOSABI_NONE, }; let abi_version = 0; - add_gnu_property_note(&mut file, architecture, binary_format); + add_gnu_property_note(&mut file, architecture, binary_format, endianness); file.flags = FileFlags::Elf { os_abi, abi_version, e_flags }; Some(file) } diff --git a/tests/run-make/branch-protection-check-IBT/Makefile b/tests/run-make/branch-protection-check-IBT/Makefile new file mode 100644 index 00000000000..cabe951e1c5 --- /dev/null +++ b/tests/run-make/branch-protection-check-IBT/Makefile @@ -0,0 +1,15 @@ +# Check for GNU Property Note + +include ../tools.mk + +# How to run this +# python3 x.py test --target x86_64-unknown-linux-gnu tests/run-make/branch-protection-check-IBT/ + +# only-x86_64 + +all: +ifeq ($(filter x86,$(LLVM_COMPONENTS)),x86_64) + $(RUSTC) --target x86_64-unknown-linux-gnu -Z cf-protection=branch -L$(TMPDIR) -C link-args='-nostartfiles' -C save-temps ./main.rs -o $(TMPDIR)/rsmain + readelf -nW $(TMPDIR)/rsmain | $(CGREP) -e ".note.gnu.property" +endif + diff --git a/tests/run-make/branch-protection-check-IBT/main.rs b/tests/run-make/branch-protection-check-IBT/main.rs new file mode 100644 index 00000000000..ad379d6ea43 --- /dev/null +++ b/tests/run-make/branch-protection-check-IBT/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("hello world"); +} From 1fc0442f7e6eaf0848ceb7230df9fe03d4e6630d Mon Sep 17 00:00:00 2001 From: Charisee Date: Fri, 5 May 2023 19:06:14 +0000 Subject: [PATCH 12/26] rewriting match on endianness --- compiler/rustc_codegen_ssa/src/back/metadata.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index d4515a794ee..ab805089be5 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -117,10 +117,17 @@ fn add_gnu_property_note( let n_descsz: u32 = 16; // Size of the n_desc field let n_type: u32 = NT_GNU_PROPERTY_TYPE_0; // Type of note descriptor let header_values = [n_namsz, n_descsz, n_type]; + header_values.iter().for_each(|v| { + data.extend_from_slice(&match endianness { + Endianness::Little => v.to_le_bytes(), + Endianness::Big => v.to_be_bytes(), + }) + }); + /* match endianness { Endianness::Little => header_values.map(|v| data.extend_from_slice(&(v.to_le_bytes()))), Endianness::Big => header_values.map(|v| data.extend_from_slice(&(v.to_be_bytes()))), - }; + };*/ data.extend_from_slice(b"GNU\0"); // Owner of the program property note let pr_type: u32 = match architecture { Architecture::X86_64 => 0xc0000002, From 59ecbd2cea20839f1288b917cbf5ba8c23864df7 Mon Sep 17 00:00:00 2001 From: est31 Date: Thu, 19 Jan 2023 10:24:17 +0100 Subject: [PATCH 13/26] Add parsing for builtin # in expression and item context --- compiler/rustc_parse/messages.ftl | 4 +++ compiler/rustc_parse/src/errors.rs | 15 +++++++++ compiler/rustc_parse/src/parser/expr.rs | 42 +++++++++++++++++++++++++ compiler/rustc_parse/src/parser/item.rs | 8 +++++ compiler/rustc_parse/src/parser/stmt.rs | 6 +++- compiler/rustc_span/src/symbol.rs | 1 + tests/ui/parser/builtin-syntax.rs | 7 +++++ tests/ui/parser/builtin-syntax.stderr | 14 +++++++++ 8 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 tests/ui/parser/builtin-syntax.rs create mode 100644 tests/ui/parser/builtin-syntax.stderr diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index cd296dca133..711447a0af0 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -257,6 +257,10 @@ parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are inva .tuple_exception_line_2 = on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access .tuple_exception_line_3 = see issue #60210 for more information +parse_expected_builtin_ident = expected identifier after `builtin #` + +parse_unknown_builtin_construct = unknown `builtin #` construct `{$name}` + parse_non_string_abi_literal = non-string ABI literal .suggestion = specify the ABI with a string literal diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 010a13aefa4..0810f0efef9 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -2644,3 +2644,18 @@ pub(crate) struct MalformedCfgAttr { pub span: Span, pub sugg: &'static str, } + +#[derive(Diagnostic)] +#[diag(parse_unknown_builtin_construct)] +pub(crate) struct UnknownBuiltinConstruct { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(parse_expected_builtin_ident)] +pub(crate) struct ExpectedBuiltinIdent { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 61396ee0d4a..844cf335962 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1300,6 +1300,8 @@ impl<'a> Parser<'a> { }) } else if self.check(&token::OpenDelim(Delimiter::Bracket)) { self.parse_expr_array_or_repeat(Delimiter::Bracket) + } else if self.is_builtin() { + self.parse_expr_builtin() } else if self.check_path() { self.parse_expr_path_start() } else if self.check_keyword(kw::Move) @@ -1755,6 +1757,42 @@ impl<'a> Parser<'a> { self.maybe_recover_from_bad_qpath(expr) } + /// Parse `builtin # ident(args,*)`. + fn parse_expr_builtin(&mut self) -> PResult<'a, P> { + self.parse_builtin(|_this, _lo, _ident| { + Ok(None) + }) + } + + pub(crate) fn parse_builtin( + &mut self, + parse: impl FnOnce(&mut Parser<'a>, Span, Ident) -> PResult<'a, Option>, + ) -> PResult<'a, T> { + let lo = self.token.span; + + self.bump(); // `builtin` + self.bump(); // `#` + + let Some((ident, false)) = self.token.ident() else { + let err = errors::ExpectedBuiltinIdent { span: self.token.span } + .into_diagnostic(&self.sess.span_diagnostic); + return Err(err); + }; + self.bump(); + + self.expect(&TokenKind::OpenDelim(Delimiter::Parenthesis))?; + let ret = if let Some(res) = parse(self, lo, ident)? { + Ok(res) + } else { + let err = errors::UnknownBuiltinConstruct { span: lo.to(ident.span), name: ident.name } + .into_diagnostic(&self.sess.span_diagnostic); + return Err(err); + }; + self.expect(&TokenKind::CloseDelim(Delimiter::Parenthesis))?; + + ret + } + /// Returns a string literal if the next token is a string literal. /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind, /// and returns `None` if the next token is not literal at all. @@ -2824,6 +2862,10 @@ impl<'a> Parser<'a> { }) } + pub(crate) fn is_builtin(&self) -> bool { + self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound) + } + /// Parses a `try {...}` expression (`try` token already eaten). fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P> { let (attrs, body) = self.parse_inner_attrs_and_block()?; diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 6ca88200dc5..edfe316ec95 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -265,6 +265,9 @@ impl<'a> Parser<'a> { // UNION ITEM self.bump(); // `union` self.parse_item_union()? + } else if self.is_builtin() { + // BUILTIN# ITEM + return self.parse_item_builtin(); } else if self.eat_keyword(kw::Macro) { // MACROS 2.0 ITEM self.parse_item_decl_macro(lo)? @@ -434,6 +437,11 @@ impl<'a> Parser<'a> { } } + fn parse_item_builtin(&mut self) -> PResult<'a, Option> { + // To be expanded + return Ok(None); + } + /// Parses an item macro, e.g., `item!();`. fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> { let path = self.parse_path(PathStyle::Mod)?; // `foo::bar` diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 1c17de337e8..a0bd086053e 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -90,7 +90,11 @@ impl<'a> Parser<'a> { attrs, errors::InvalidVariableDeclarationSub::UseLetNotVar, )? - } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() { + } else if self.check_path() + && !self.token.is_qpath_start() + && !self.is_path_start_item() + && !self.is_builtin() + { // We have avoided contextual keywords like `union`, items with `crate` visibility, // or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something // that starts like a path (1 token), but it fact not a path. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 58015d5d502..9e543fc8de4 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -95,6 +95,7 @@ symbols! { // Weak keywords, have special meaning only in specific contexts. Auto: "auto", + Builtin: "builtin", Catch: "catch", Default: "default", MacroRules: "macro_rules", diff --git a/tests/ui/parser/builtin-syntax.rs b/tests/ui/parser/builtin-syntax.rs new file mode 100644 index 00000000000..c0b91a58073 --- /dev/null +++ b/tests/ui/parser/builtin-syntax.rs @@ -0,0 +1,7 @@ +fn main() { + builtin # foobar(); //~ ERROR unknown `builtin #` construct +} + +fn not_identifier() { + builtin # {}(); //~ ERROR expected identifier after +} diff --git a/tests/ui/parser/builtin-syntax.stderr b/tests/ui/parser/builtin-syntax.stderr new file mode 100644 index 00000000000..2679049fb5e --- /dev/null +++ b/tests/ui/parser/builtin-syntax.stderr @@ -0,0 +1,14 @@ +error: unknown `builtin #` construct `foobar` + --> $DIR/builtin-syntax.rs:2:5 + | +LL | builtin # foobar(); + | ^^^^^^^^^^^^^^^^ + +error: expected identifier after `builtin #` + --> $DIR/builtin-syntax.rs:6:15 + | +LL | builtin # {}(); + | ^ + +error: aborting due to 2 previous errors + From 5eb29c7f49c2d99e9bfc778f30984f7fdcf5fc08 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 22 Apr 2023 16:29:34 +0200 Subject: [PATCH 14/26] Migrate offset_of from a macro to builtin # syntax --- .../rustc_ast_pretty/src/pprust/state/expr.rs | 3 +- compiler/rustc_builtin_macros/messages.ftl | 4 - compiler/rustc_builtin_macros/src/lib.rs | 2 - .../rustc_builtin_macros/src/offset_of.rs | 99 ------------------- compiler/rustc_parse/src/parser/expr.rs | 20 +++- compiler/rustc_span/src/symbol.rs | 1 + library/core/src/mem/mod.rs | 6 +- .../offset_of.concrete.ConstProp.diff | 16 +-- .../offset_of.generic.ConstProp.diff | 8 +- tests/ui/offset-of/offset-of-arg-count.rs | 14 ++- tests/ui/offset-of/offset-of-arg-count.stderr | 59 +++++++++-- tests/ui/offset-of/offset-of-builtin.rs | 44 +++++++++ tests/ui/offset-of/offset-of-builtin.stderr | 65 ++++++++++++ tests/ui/offset-of/offset-of-dst-field.stderr | 3 + tests/ui/offset-of/offset-of-unstable.stderr | 5 + 15 files changed, 213 insertions(+), 136 deletions(-) delete mode 100644 compiler/rustc_builtin_macros/src/offset_of.rs create mode 100644 tests/ui/offset-of/offset-of-builtin.rs create mode 100644 tests/ui/offset-of/offset-of-builtin.stderr diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs index b74c59bca30..87c32ffce12 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs @@ -556,8 +556,7 @@ impl<'a> State<'a> { self.pclose(); } ast::ExprKind::OffsetOf(container, fields) => { - // FIXME: This should have its own syntax, distinct from a macro invocation. - self.word("offset_of!"); + self.word("builtin # offset_of"); self.popen(); self.rbox(0, Inconsistent); self.print_type(container); diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl index 0d7cf7cdb26..3b458b1d30b 100644 --- a/compiler/rustc_builtin_macros/messages.ftl +++ b/compiler/rustc_builtin_macros/messages.ftl @@ -150,10 +150,6 @@ builtin_macros_format_pos_mismatch = {$n} positional {$n -> *[more] arguments } in format string, but {$desc} -builtin_macros_offset_of_expected_field = expected field - -builtin_macros_offset_of_expected_two_args = expected 2 arguments - builtin_macros_test_case_non_item = `#[test_case]` attribute is only allowed on items builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index c7da61d72b3..4e5edb4d6b1 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -44,7 +44,6 @@ mod format; mod format_foreign; mod global_allocator; mod log_syntax; -mod offset_of; mod source_util; mod test; mod trace_macros; @@ -92,7 +91,6 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { line: source_util::expand_line, log_syntax: log_syntax::expand_log_syntax, module_path: source_util::expand_mod, - offset_of: offset_of::expand_offset_of, option_env: env::expand_option_env, core_panic: edition_panic::expand_panic, std_panic: edition_panic::expand_panic, diff --git a/compiler/rustc_builtin_macros/src/offset_of.rs b/compiler/rustc_builtin_macros/src/offset_of.rs deleted file mode 100644 index 0ef3e000e41..00000000000 --- a/compiler/rustc_builtin_macros/src/offset_of.rs +++ /dev/null @@ -1,99 +0,0 @@ -use rustc_ast as ast; -use rustc_ast::ptr::P; -use rustc_ast::token; -use rustc_ast::tokenstream::TokenStream; -use rustc_errors::PResult; -use rustc_expand::base::{self, *}; -use rustc_macros::Diagnostic; -use rustc_parse::parser::Parser; -use rustc_span::{symbol::Ident, Span}; - -#[derive(Diagnostic)] -#[diag(builtin_macros_offset_of_expected_field)] -struct ExpectedField { - #[primary_span] - span: Span, -} - -#[derive(Diagnostic)] -#[diag(builtin_macros_offset_of_expected_two_args)] -struct ExpectedTwoArgs { - #[primary_span] - span: Span, -} - -fn parse_field<'a>(cx: &ExtCtxt<'a>, p: &mut Parser<'a>) -> PResult<'a, Ident> { - let token = p.token.uninterpolate(); - let field = match token.kind { - token::Ident(name, _) => Ident::new(name, token.span), - token::Literal(token::Lit { kind: token::Integer, symbol, suffix: None }) => { - Ident::new(symbol, token.span) - } - _ => return Err(cx.create_err(ExpectedField { span: p.token.span })), - }; - - p.bump(); - - Ok(field) -} - -fn parse_args<'a>( - cx: &mut ExtCtxt<'a>, - sp: Span, - tts: TokenStream, -) -> PResult<'a, (P, P<[Ident]>)> { - let mut p = cx.new_parser_from_tts(tts); - - let container = p.parse_ty()?; - - p.expect(&token::Comma)?; - - if p.eat(&token::Eof) { - return Err(cx.create_err(ExpectedTwoArgs { span: sp })); - } - - let mut fields = Vec::new(); - - loop { - let field = parse_field(cx, &mut p)?; - fields.push(field); - - if p.eat(&token::Dot) { - continue; - } - - p.eat(&token::Comma); - - if !p.eat(&token::Eof) { - return Err(cx.create_err(ExpectedTwoArgs { span: sp })); - } - - break; - } - - Ok((container, fields.into())) -} - -pub fn expand_offset_of<'cx>( - cx: &'cx mut ExtCtxt<'_>, - sp: Span, - tts: TokenStream, -) -> Box { - match parse_args(cx, sp, tts) { - Ok((container, fields)) => { - let expr = P(ast::Expr { - id: ast::DUMMY_NODE_ID, - kind: ast::ExprKind::OffsetOf(container, fields), - span: sp, - attrs: ast::AttrVec::new(), - tokens: None, - }); - - MacEager::expr(expr) - } - Err(mut err) => { - err.emit(); - DummyResult::any(sp) - } - } -} diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 844cf335962..b84a088a7b7 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1759,7 +1759,11 @@ impl<'a> Parser<'a> { /// Parse `builtin # ident(args,*)`. fn parse_expr_builtin(&mut self) -> PResult<'a, P> { - self.parse_builtin(|_this, _lo, _ident| { + self.parse_builtin(|this, lo, ident| { + if ident.name == sym::offset_of { + return Ok(Some(this.parse_expr_offset_of(lo)?)); + } + Ok(None) }) } @@ -1793,6 +1797,20 @@ impl<'a> Parser<'a> { ret } + pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, P> { + let container = self.parse_ty()?; + self.expect(&TokenKind::Comma)?; + + let seq_sep = SeqSep { sep: Some(token::Dot), trailing_sep_allowed: false }; + let (fields, _trailing, _recovered) = self.parse_seq_to_before_end( + &TokenKind::CloseDelim(Delimiter::Parenthesis), + seq_sep, + Parser::parse_field_name, + )?; + let span = lo.to(self.token.span); + Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields.to_vec().into()))) + } + /// Returns a string literal if the next token is a string literal. /// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind, /// and returns `None` if the next token is not literal at all. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 9e543fc8de4..d54a615dd4a 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -441,6 +441,7 @@ symbols! { breakpoint, bridge, bswap, + builtin_syntax, c_str, c_str_literals, c_unwind, diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 7d2f2971523..4913a6de918 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -1315,9 +1315,9 @@ impl SizedTypeProperties for T {} /// /// assert_eq!(mem::offset_of!(NestedA, b.0), 0); /// ``` -#[unstable(feature = "offset_of", issue = "106655")] -#[rustc_builtin_macro] #[cfg(not(bootstrap))] +#[unstable(feature = "offset_of", issue = "106655")] +#[allow_internal_unstable(builtin_syntax)] pub macro offset_of($Container:ty, $($fields:tt).+ $(,)?) { - /* compiler built-in */ + builtin # offset_of($Container, $($fields).+) } diff --git a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff index e768a47a96d..e3757941c8c 100644 --- a/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff +++ b/tests/mir-opt/const_prop/offset_of.concrete.ConstProp.diff @@ -22,17 +22,17 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/offset_of.rs:+1:9: +1:10 -- _1 = OffsetOf(Alpha, [0]); // scope 0 at $DIR/offset_of.rs:+1:13: +1:33 -+ _1 = const 4_usize; // scope 0 at $DIR/offset_of.rs:+1:13: +1:33 +- _1 = OffsetOf(Alpha, [0]); // scope 0 at $SRC_DIR/core/src/mem/mod.rs:LL:COL ++ _1 = const 4_usize; // scope 0 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageLive(_2); // scope 1 at $DIR/offset_of.rs:+2:9: +2:10 -- _2 = OffsetOf(Alpha, [1]); // scope 1 at $DIR/offset_of.rs:+2:13: +2:33 -+ _2 = const 0_usize; // scope 1 at $DIR/offset_of.rs:+2:13: +2:33 +- _2 = OffsetOf(Alpha, [1]); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL ++ _2 = const 0_usize; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageLive(_3); // scope 2 at $DIR/offset_of.rs:+3:9: +3:11 -- _3 = OffsetOf(Alpha, [2, 0]); // scope 2 at $DIR/offset_of.rs:+3:14: +3:36 -+ _3 = const 2_usize; // scope 2 at $DIR/offset_of.rs:+3:14: +3:36 +- _3 = OffsetOf(Alpha, [2, 0]); // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL ++ _3 = const 2_usize; // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageLive(_4); // scope 3 at $DIR/offset_of.rs:+4:9: +4:11 -- _4 = OffsetOf(Alpha, [2, 1]); // scope 3 at $DIR/offset_of.rs:+4:14: +4:36 -+ _4 = const 3_usize; // scope 3 at $DIR/offset_of.rs:+4:14: +4:36 +- _4 = OffsetOf(Alpha, [2, 1]); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL ++ _4 = const 3_usize; // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/offset_of.rs:+0:15: +5:2 StorageDead(_4); // scope 3 at $DIR/offset_of.rs:+5:1: +5:2 StorageDead(_3); // scope 2 at $DIR/offset_of.rs:+5:1: +5:2 diff --git a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff index e40fdbd79d8..4a655604cd1 100644 --- a/tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff +++ b/tests/mir-opt/const_prop/offset_of.generic.ConstProp.diff @@ -22,13 +22,13 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/offset_of.rs:+1:9: +1:11 - _1 = OffsetOf(Gamma, [0]); // scope 0 at $DIR/offset_of.rs:+1:14: +1:37 + _1 = OffsetOf(Gamma, [0]); // scope 0 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageLive(_2); // scope 1 at $DIR/offset_of.rs:+2:9: +2:11 - _2 = OffsetOf(Gamma, [1]); // scope 1 at $DIR/offset_of.rs:+2:14: +2:37 + _2 = OffsetOf(Gamma, [1]); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageLive(_3); // scope 2 at $DIR/offset_of.rs:+3:9: +3:11 - _3 = OffsetOf(Delta, [1]); // scope 2 at $DIR/offset_of.rs:+3:14: +3:37 + _3 = OffsetOf(Delta, [1]); // scope 2 at $SRC_DIR/core/src/mem/mod.rs:LL:COL StorageLive(_4); // scope 3 at $DIR/offset_of.rs:+4:9: +4:11 - _4 = OffsetOf(Delta, [2]); // scope 3 at $DIR/offset_of.rs:+4:14: +4:37 + _4 = OffsetOf(Delta, [2]); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/offset_of.rs:+0:17: +5:2 StorageDead(_4); // scope 3 at $DIR/offset_of.rs:+5:1: +5:2 StorageDead(_3); // scope 2 at $DIR/offset_of.rs:+5:1: +5:2 diff --git a/tests/ui/offset-of/offset-of-arg-count.rs b/tests/ui/offset-of/offset-of-arg-count.rs index 163b07454ec..5e66e33f8a2 100644 --- a/tests/ui/offset-of/offset-of-arg-count.rs +++ b/tests/ui/offset-of/offset-of-arg-count.rs @@ -3,7 +3,15 @@ use std::mem::offset_of; fn main() { - offset_of!(NotEnoughArguments); //~ ERROR expected one of - offset_of!(NotEnoughArgumentsWithAComma, ); //~ ERROR expected 2 arguments - offset_of!(Container, field, too many arguments); //~ ERROR expected 2 arguments + offset_of!(NotEnoughArguments); //~ ERROR unexpected end of macro invocation + offset_of!(NotEnoughArgumentsWithAComma, ); //~ ERROR unexpected end of macro invocation + offset_of!(Container, field, too many arguments); //~ ERROR no rules expected the token `too` + offset_of!(S, f); // compiles fine + offset_of!(S, f,); // also compiles fine + offset_of!(S, f.); //~ ERROR unexpected end of macro invocation + offset_of!(S, f.,); //~ ERROR expected identifier + offset_of!(S, f..); //~ ERROR no rules expected the token + offset_of!(S, f..,); //~ ERROR no rules expected the token } + +struct S { f: u8, } diff --git a/tests/ui/offset-of/offset-of-arg-count.stderr b/tests/ui/offset-of/offset-of-arg-count.stderr index ebecc982c51..4275a89545f 100644 --- a/tests/ui/offset-of/offset-of-arg-count.stderr +++ b/tests/ui/offset-of/offset-of-arg-count.stderr @@ -1,20 +1,59 @@ -error: expected one of `!`, `(`, `+`, `,`, `::`, or `<`, found `` - --> $DIR/offset-of-arg-count.rs:6:16 +error: unexpected end of macro invocation + --> $DIR/offset-of-arg-count.rs:6:34 | LL | offset_of!(NotEnoughArguments); - | ^^^^^^^^^^^^^^^^^^ expected one of `!`, `(`, `+`, `,`, `::`, or `<` + | ^ missing tokens in macro arguments + | +note: while trying to match `,` + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL -error: expected 2 arguments - --> $DIR/offset-of-arg-count.rs:7:5 +error: unexpected end of macro invocation + --> $DIR/offset-of-arg-count.rs:7:45 | LL | offset_of!(NotEnoughArgumentsWithAComma, ); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^ missing tokens in macro arguments + | +note: while trying to match meta-variable `$fields:tt` + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL -error: expected 2 arguments - --> $DIR/offset-of-arg-count.rs:8:5 +error: no rules expected the token `too` + --> $DIR/offset-of-arg-count.rs:8:34 | LL | offset_of!(Container, field, too many arguments); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^ no rules expected this token in macro call + | + = note: while trying to match sequence end -error: aborting due to 3 previous errors +error: unexpected end of macro invocation + --> $DIR/offset-of-arg-count.rs:11:21 + | +LL | offset_of!(S, f.); + | ^ missing tokens in macro arguments + | +note: while trying to match meta-variable `$fields:tt` + --> $SRC_DIR/core/src/mem/mod.rs:LL:COL + +error: expected identifier, found `,` + --> $DIR/offset-of-arg-count.rs:12:21 + | +LL | offset_of!(S, f.,); + | ^ expected identifier + +error: no rules expected the token `..` + --> $DIR/offset-of-arg-count.rs:13:20 + | +LL | offset_of!(S, f..); + | ^^ no rules expected this token in macro call + | + = note: while trying to match sequence start + +error: no rules expected the token `..` + --> $DIR/offset-of-arg-count.rs:14:20 + | +LL | offset_of!(S, f..,); + | ^^ no rules expected this token in macro call + | + = note: while trying to match sequence start + +error: aborting due to 7 previous errors diff --git a/tests/ui/offset-of/offset-of-builtin.rs b/tests/ui/offset-of/offset-of-builtin.rs new file mode 100644 index 00000000000..dcc58e842a0 --- /dev/null +++ b/tests/ui/offset-of/offset-of-builtin.rs @@ -0,0 +1,44 @@ +// For the exposed macro we already test these errors in the other files, +// but this test helps to make sure the builtin construct also errors. +// This has the same examples as offset-of-arg-count.rs + + + +fn main() { + builtin # offset_of(NotEnoughArguments); //~ ERROR expected one of +} +fn t1() { + // Already errored upon at the macro level. Yielding an error would require + // extra effort. + builtin # offset_of(NotEnoughArgumentsWithAComma, ); +} +fn t2() { + builtin # offset_of(Container, field, too many arguments); //~ ERROR expected identifier, found + //~| ERROR found `,` + //~| ERROR found `many` + //~| ERROR found `arguments` +} +fn t3() { + builtin # offset_of(S, f); // compiles fine +} +fn t4() { + // Already errored upon at the macro level. Yielding an error would require + // extra effort. + builtin # offset_of(S, f); +} +fn t5() { + builtin # offset_of(S, f.); //~ ERROR expected identifier +} +fn t6() { + builtin # offset_of(S, f.,); //~ ERROR expected identifier +} +fn t7() { + builtin # offset_of(S, f..); //~ ERROR expected one of +} +fn t8() { + // Already errored upon at the macro level. Yielding an error would require + // extra effort. + builtin # offset_of(S, f..,); +} + +struct S { f: u8, } diff --git a/tests/ui/offset-of/offset-of-builtin.stderr b/tests/ui/offset-of/offset-of-builtin.stderr new file mode 100644 index 00000000000..1a1f33cc613 --- /dev/null +++ b/tests/ui/offset-of/offset-of-builtin.stderr @@ -0,0 +1,65 @@ +error: expected one of `!`, `(`, `+`, `,`, `::`, or `<`, found `)` + --> $DIR/offset-of-builtin.rs:8:43 + | +LL | builtin # offset_of(NotEnoughArguments); + | ^ expected one of `!`, `(`, `+`, `,`, `::`, or `<` + +error: expected identifier, found `,` + --> $DIR/offset-of-builtin.rs:16:41 + | +LL | builtin # offset_of(Container, field, too many arguments); + | ^ + | | + | expected identifier + | help: remove this comma + +error: expected one of `)` or `.`, found `,` + --> $DIR/offset-of-builtin.rs:16:41 + | +LL | builtin # offset_of(Container, field, too many arguments); + | ^ + | | + | expected one of `)` or `.` + | help: missing `.` + +error: expected one of `)` or `.`, found `many` + --> $DIR/offset-of-builtin.rs:16:47 + | +LL | builtin # offset_of(Container, field, too many arguments); + | -^^^^ expected one of `)` or `.` + | | + | help: missing `.` + +error: expected one of `)` or `.`, found `arguments` + --> $DIR/offset-of-builtin.rs:16:52 + | +LL | builtin # offset_of(Container, field, too many arguments); + | -^^^^^^^^^ expected one of `)` or `.` + | | + | help: missing `.` + +error: expected identifier, found `)` + --> $DIR/offset-of-builtin.rs:30:30 + | +LL | builtin # offset_of(S, f.); + | ^ expected identifier + +error: expected identifier, found `,` + --> $DIR/offset-of-builtin.rs:33:30 + | +LL | builtin # offset_of(S, f.,); + | ^ expected identifier + +error: expected one of `)` or `.`, found `..` + --> $DIR/offset-of-builtin.rs:36:29 + | +LL | builtin # offset_of(S, f..); + | ^^ expected one of `)` or `.` + | +help: if you meant to bind the contents of the rest of the array pattern into `f`, use `@` + | +LL | builtin # offset_of(S, f @ ..); + | + + +error: aborting due to 8 previous errors + diff --git a/tests/ui/offset-of/offset-of-dst-field.stderr b/tests/ui/offset-of/offset-of-dst-field.stderr index 8e88015b07a..e6e0f499236 100644 --- a/tests/ui/offset-of/offset-of-dst-field.stderr +++ b/tests/ui/offset-of/offset-of-dst-field.stderr @@ -5,6 +5,7 @@ LL | offset_of!(Alpha, z); | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `[u8]` + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `(dyn Trait + 'static)` cannot be known at compilation time --> $DIR/offset-of-dst-field.rs:31:5 @@ -13,6 +14,7 @@ LL | offset_of!(Beta, z); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `(dyn Trait + 'static)` + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the size for values of type `Extern` cannot be known at compilation time --> $DIR/offset-of-dst-field.rs:32:5 @@ -21,6 +23,7 @@ LL | offset_of!(Gamma, z); | ^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | = help: the trait `Sized` is not implemented for `Extern` + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/tests/ui/offset-of/offset-of-unstable.stderr b/tests/ui/offset-of/offset-of-unstable.stderr index 25811a061d7..c39882519a5 100644 --- a/tests/ui/offset-of/offset-of-unstable.stderr +++ b/tests/ui/offset-of/offset-of-unstable.stderr @@ -33,6 +33,7 @@ LL | | ); | |_____^ | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/offset-of-unstable.rs:18:5 @@ -41,6 +42,7 @@ LL | offset_of!(StableWithUnstableField, unstable); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/offset-of-unstable.rs:20:5 @@ -49,6 +51,7 @@ LL | offset_of!(StableWithUnstableFieldType, stable.unstable); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/offset-of-unstable.rs:21:5 @@ -61,6 +64,7 @@ LL | | ); | |_____^ | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0658]: use of unstable library feature 'unstable_test_feature' --> $DIR/offset-of-unstable.rs:26:5 @@ -73,6 +77,7 @@ LL | | ); | |_____^ | = help: add `#![feature(unstable_test_feature)]` to the crate attributes to enable + = note: this error originates in the macro `offset_of` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 8 previous errors From 83b4df4e611961373ffaf4bfcd9f8940a4f37c09 Mon Sep 17 00:00:00 2001 From: est31 Date: Sat, 29 Apr 2023 14:57:26 +0200 Subject: [PATCH 15/26] Add feature gate --- compiler/rustc_ast_passes/src/feature_gate.rs | 1 + compiler/rustc_feature/src/active.rs | 2 ++ compiler/rustc_parse/src/parser/expr.rs | 1 + .../ui/feature-gates/feature-gate-builtin_syntax.rs | 7 +++++++ .../feature-gates/feature-gate-builtin_syntax.stderr | 12 ++++++++++++ tests/ui/offset-of/offset-of-builtin.rs | 4 ++-- tests/ui/parser/builtin-syntax.rs | 2 ++ tests/ui/parser/builtin-syntax.stderr | 4 ++-- 8 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 tests/ui/feature-gates/feature-gate-builtin_syntax.rs create mode 100644 tests/ui/feature-gates/feature-gate-builtin_syntax.stderr diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index b960671bf6e..3d5056d82c5 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -603,6 +603,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) { gate_all!(yeet_expr, "`do yeet` expression is experimental"); gate_all!(dyn_star, "`dyn*` trait objects are experimental"); gate_all!(const_closures, "const closures are experimental"); + gate_all!(builtin_syntax, "`builtin #` syntax is unstable"); if !visitor.features.negative_bounds { for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() { diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs index 7e7df0e9584..a797dd94404 100644 --- a/compiler/rustc_feature/src/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -313,6 +313,8 @@ declare_features! ( (active, async_closure, "1.37.0", Some(62290), None), /// Allows async functions to be declared, implemented, and used in traits. (active, async_fn_in_trait, "1.66.0", Some(91611), None), + /// Allows builtin # foo() syntax + (active, builtin_syntax, "CURRENT_RUSTC_VERSION", Some(110680), None), /// Allows `c"foo"` literals. (active, c_str_literals, "CURRENT_RUSTC_VERSION", Some(105723), None), /// Treat `extern "C"` function as nounwind. diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index b84a088a7b7..c1095512bd4 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1782,6 +1782,7 @@ impl<'a> Parser<'a> { .into_diagnostic(&self.sess.span_diagnostic); return Err(err); }; + self.sess.gated_spans.gate(sym::builtin_syntax, ident.span); self.bump(); self.expect(&TokenKind::OpenDelim(Delimiter::Parenthesis))?; diff --git a/tests/ui/feature-gates/feature-gate-builtin_syntax.rs b/tests/ui/feature-gates/feature-gate-builtin_syntax.rs new file mode 100644 index 00000000000..832bb5a96bc --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-builtin_syntax.rs @@ -0,0 +1,7 @@ +struct Foo { + v: u8, + w: u8, +} +fn main() { + builtin # offset_of(Foo, v); //~ ERROR `builtin #` syntax is unstable +} diff --git a/tests/ui/feature-gates/feature-gate-builtin_syntax.stderr b/tests/ui/feature-gates/feature-gate-builtin_syntax.stderr new file mode 100644 index 00000000000..3bc7848f66d --- /dev/null +++ b/tests/ui/feature-gates/feature-gate-builtin_syntax.stderr @@ -0,0 +1,12 @@ +error[E0658]: `builtin #` syntax is unstable + --> $DIR/feature-gate-builtin_syntax.rs:6:15 + | +LL | builtin # offset_of(Foo, v); + | ^^^^^^^^^ + | + = note: see issue #110680 for more information + = help: add `#![feature(builtin_syntax)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/tests/ui/offset-of/offset-of-builtin.rs b/tests/ui/offset-of/offset-of-builtin.rs index dcc58e842a0..1be9899887b 100644 --- a/tests/ui/offset-of/offset-of-builtin.rs +++ b/tests/ui/offset-of/offset-of-builtin.rs @@ -1,9 +1,9 @@ +#![feature(builtin_syntax)] + // For the exposed macro we already test these errors in the other files, // but this test helps to make sure the builtin construct also errors. // This has the same examples as offset-of-arg-count.rs - - fn main() { builtin # offset_of(NotEnoughArguments); //~ ERROR expected one of } diff --git a/tests/ui/parser/builtin-syntax.rs b/tests/ui/parser/builtin-syntax.rs index c0b91a58073..897dab8ec50 100644 --- a/tests/ui/parser/builtin-syntax.rs +++ b/tests/ui/parser/builtin-syntax.rs @@ -1,3 +1,5 @@ +#![feature(builtin_syntax)] + fn main() { builtin # foobar(); //~ ERROR unknown `builtin #` construct } diff --git a/tests/ui/parser/builtin-syntax.stderr b/tests/ui/parser/builtin-syntax.stderr index 2679049fb5e..ee3764a6221 100644 --- a/tests/ui/parser/builtin-syntax.stderr +++ b/tests/ui/parser/builtin-syntax.stderr @@ -1,11 +1,11 @@ error: unknown `builtin #` construct `foobar` - --> $DIR/builtin-syntax.rs:2:5 + --> $DIR/builtin-syntax.rs:4:5 | LL | builtin # foobar(); | ^^^^^^^^^^^^^^^^ error: expected identifier after `builtin #` - --> $DIR/builtin-syntax.rs:6:15 + --> $DIR/builtin-syntax.rs:8:15 | LL | builtin # {}(); | ^ From 37f3e2f4b115b166518a208950ecaaef1434830b Mon Sep 17 00:00:00 2001 From: Charisee Date: Fri, 5 May 2023 19:47:00 +0000 Subject: [PATCH 16/26] rewriting match on endianness --- compiler/rustc_codegen_ssa/src/back/metadata.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs index ab805089be5..8968133bac5 100644 --- a/compiler/rustc_codegen_ssa/src/back/metadata.rs +++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs @@ -123,11 +123,6 @@ fn add_gnu_property_note( Endianness::Big => v.to_be_bytes(), }) }); - /* - match endianness { - Endianness::Little => header_values.map(|v| data.extend_from_slice(&(v.to_le_bytes()))), - Endianness::Big => header_values.map(|v| data.extend_from_slice(&(v.to_be_bytes()))), - };*/ data.extend_from_slice(b"GNU\0"); // Owner of the program property note let pr_type: u32 = match architecture { Architecture::X86_64 => 0xc0000002, @@ -138,10 +133,12 @@ fn add_gnu_property_note( let pr_data: u32 = 3; //program property descriptor let pr_padding: u32 = 0; let property_values = [pr_type, pr_datasz, pr_data, pr_padding]; - match endianness { - Endianness::Little => property_values.map(|v| data.extend_from_slice(&(v.to_le_bytes()))), - Endianness::Big => property_values.map(|v| data.extend_from_slice(&(v.to_be_bytes()))), - }; + property_values.iter().for_each(|v| { + data.extend_from_slice(&match endianness { + Endianness::Little => v.to_le_bytes(), + Endianness::Big => v.to_be_bytes(), + }) + }); file.append_section_data(section, &data, 8); } From f46eabb9e56fab132ec8171d0e0239f42c986e52 Mon Sep 17 00:00:00 2001 From: Matthew Jasper Date: Fri, 5 May 2023 15:52:53 +0100 Subject: [PATCH 17/26] Report nicer lifetime errors for specialization Add an obligation cause for these error so that the error points to the implementations that caused the error. --- .../src/impl_wf_check/min_specialization.rs | 19 +++++-- .../src/traits/coherence.rs | 4 +- .../rustc_trait_selection/src/traits/mod.rs | 4 +- .../src/traits/specialize/mod.rs | 34 +++++++++++-- .../rustc_trait_selection/src/traits/util.rs | 4 +- .../specialize_with_generalize_lifetimes.rs | 50 +++++++++++++++++++ ...pecialize_with_generalize_lifetimes.stderr | 27 ++++++++++ 7 files changed, 132 insertions(+), 10 deletions(-) create mode 100644 tests/ui/specialization/min_specialization/specialize_with_generalize_lifetimes.rs create mode 100644 tests/ui/specialization/min_specialization/specialize_with_generalize_lifetimes.stderr diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs index 4f0df5c5677..e84da2519ae 100644 --- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs @@ -80,7 +80,7 @@ use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt}; use rustc_span::Span; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::outlives_bounds::InferCtxtExt as _; -use rustc_trait_selection::traits::{self, translate_substs, wf, ObligationCtxt}; +use rustc_trait_selection::traits::{self, translate_substs_with_cause, wf, ObligationCtxt}; pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) { if let Some(node) = parent_specialization_node(tcx, impl_def_id) { @@ -180,8 +180,21 @@ fn get_impl_substs( ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id); let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id); - let impl2_substs = - translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node); + let impl1_span = tcx.def_span(impl1_def_id); + let impl2_substs = translate_substs_with_cause( + infcx, + param_env, + impl1_def_id.to_def_id(), + impl1_substs, + impl2_node, + |_, span| { + traits::ObligationCause::new( + impl1_span, + impl1_def_id, + traits::ObligationCauseCode::BindingObligation(impl2_node.def_id(), span), + ) + }, + ); let errors = ocx.select_all_or_error(); if !errors.is_empty() { diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index b7690f79933..9f405aaf1a8 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -322,7 +322,9 @@ fn negative_impl(tcx: TyCtxt<'_>, impl1_def_id: DefId, impl2_def_id: DefId) -> b let selcx = &mut SelectionContext::new(&infcx); let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id); let (subject2, obligations) = - impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs); + impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs, |_, _| { + ObligationCause::dummy() + }); !equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id) } diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 8b8c50f6b83..138b0fb7432 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -54,7 +54,9 @@ pub use self::select::{EvaluationCache, SelectionCache, SelectionContext}; pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError}; pub use self::specialize::specialization_graph::FutureCompatOverlapError; pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind; -pub use self::specialize::{specialization_graph, translate_substs, OverlapError}; +pub use self::specialize::{ + specialization_graph, translate_substs, translate_substs_with_cause, OverlapError, +}; pub use self::structural_match::{ search_for_adt_const_param_violation, search_for_structural_match_violation, }; diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 8bbebadb22a..9a4b72013b8 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -82,6 +82,30 @@ pub fn translate_substs<'tcx>( source_impl: DefId, source_substs: SubstsRef<'tcx>, target_node: specialization_graph::Node, +) -> SubstsRef<'tcx> { + translate_substs_with_cause( + infcx, + param_env, + source_impl, + source_substs, + target_node, + |_, _| ObligationCause::dummy(), + ) +} + +/// Like [translate_substs], but obligations from the parent implementation +/// are registered with the provided `ObligationCause`. +/// +/// This is for reporting *region* errors from those bounds. Type errors should +/// not happen because the specialization graph already checks for those, and +/// will result in an ICE. +pub fn translate_substs_with_cause<'tcx>( + infcx: &InferCtxt<'tcx>, + param_env: ty::ParamEnv<'tcx>, + source_impl: DefId, + source_substs: SubstsRef<'tcx>, + target_node: specialization_graph::Node, + cause: impl Fn(usize, Span) -> ObligationCause<'tcx>, ) -> SubstsRef<'tcx> { debug!( "translate_substs({:?}, {:?}, {:?}, {:?})", @@ -99,7 +123,7 @@ pub fn translate_substs<'tcx>( return source_substs; } - fulfill_implication(infcx, param_env, source_trait_ref, source_impl, target_impl) + fulfill_implication(infcx, param_env, source_trait_ref, source_impl, target_impl, cause) .unwrap_or_else(|()| { bug!( "When translating substitutions from {source_impl:?} to {target_impl:?}, \ @@ -154,7 +178,10 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId, let infcx = tcx.infer_ctxt().build(); // Attempt to prove that impl2 applies, given all of the above. - fulfill_implication(&infcx, penv, impl1_trait_ref, impl1_def_id, impl2_def_id).is_ok() + fulfill_implication(&infcx, penv, impl1_trait_ref, impl1_def_id, impl2_def_id, |_, _| { + ObligationCause::dummy() + }) + .is_ok() } /// Attempt to fulfill all obligations of `target_impl` after unification with @@ -168,6 +195,7 @@ fn fulfill_implication<'tcx>( source_trait_ref: ty::TraitRef<'tcx>, source_impl: DefId, target_impl: DefId, + error_cause: impl Fn(usize, Span) -> ObligationCause<'tcx>, ) -> Result, ()> { debug!( "fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)", @@ -195,7 +223,7 @@ fn fulfill_implication<'tcx>( let selcx = &mut SelectionContext::new(&infcx); let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl); let (target_trait, obligations) = - util::impl_subject_and_oblig(selcx, param_env, target_impl, target_substs); + util::impl_subject_and_oblig(selcx, param_env, target_impl, target_substs, error_cause); // do the impls unify? If not, no specialization. let Ok(InferOk { obligations: more_obligations, .. }) = diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 7b7e297c64b..82f3df40198 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -197,6 +197,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>( param_env: ty::ParamEnv<'tcx>, impl_def_id: DefId, impl_substs: SubstsRef<'tcx>, + cause: impl Fn(usize, Span) -> ObligationCause<'tcx>, ) -> (ImplSubject<'tcx>, impl Iterator>) { let subject = selcx.tcx().impl_subject(impl_def_id); let subject = subject.subst(selcx.tcx(), impl_substs); @@ -208,8 +209,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>( let predicates = predicates.instantiate(selcx.tcx(), impl_substs); let InferOk { value: predicates, obligations: normalization_obligations2 } = selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(predicates); - let impl_obligations = - super::predicates_for_generics(|_, _| ObligationCause::dummy(), param_env, predicates); + let impl_obligations = super::predicates_for_generics(cause, param_env, predicates); let impl_obligations = impl_obligations .chain(normalization_obligations1.into_iter()) diff --git a/tests/ui/specialization/min_specialization/specialize_with_generalize_lifetimes.rs b/tests/ui/specialization/min_specialization/specialize_with_generalize_lifetimes.rs new file mode 100644 index 00000000000..d90b81f717a --- /dev/null +++ b/tests/ui/specialization/min_specialization/specialize_with_generalize_lifetimes.rs @@ -0,0 +1,50 @@ +// Regression test for #79457. + +#![feature(min_specialization)] + +use std::any::Any; + +pub trait Tr { + fn method(self) -> Box; + fn other(self); +} + +impl Tr for T { + default fn method(self) -> Box { + Box::new(self) + } + + default fn other(self) {} +} + +impl<'a> Tr for &'a i32 { + //~^ ERROR does not fulfill the required lifetime + fn other(self) {} +} + +fn promote_to_static<'a>(i: &'a i32) -> &'static i32 { + *i.method().downcast().unwrap() +} + +struct Wrapper<'a>(&'a i32); + +impl<'a> Tr for Wrapper<'a> { + //~^ ERROR does not fulfill the required lifetime + fn other(self) {} +} + +fn promote_to_static_2<'a>(w: Wrapper<'a>) -> Wrapper<'static> { + *w.method().downcast().unwrap() +} + +fn main() { + let i = Box::new(100_i32); + let static_i: &'static i32 = promote_to_static(&*i); + drop(i); + println!("{}", *static_i); + + let j = Box::new(200_i32); + let static_w: Wrapper<'static> = promote_to_static_2(Wrapper(&*j)); + drop(j); + println!("{}", *static_w.0); +} diff --git a/tests/ui/specialization/min_specialization/specialize_with_generalize_lifetimes.stderr b/tests/ui/specialization/min_specialization/specialize_with_generalize_lifetimes.stderr new file mode 100644 index 00000000000..2af75876d5b --- /dev/null +++ b/tests/ui/specialization/min_specialization/specialize_with_generalize_lifetimes.stderr @@ -0,0 +1,27 @@ +error[E0477]: the type `&'a i32` does not fulfill the required lifetime + --> $DIR/specialize_with_generalize_lifetimes.rs:20:1 + | +LL | impl<'a> Tr for &'a i32 { + | ^^^^^^^^^^^^^^^^^^^^^^^ + | +note: type must satisfy the static lifetime as required by this binding + --> $DIR/specialize_with_generalize_lifetimes.rs:12:15 + | +LL | impl Tr for T { + | ^^^^^^^ + +error[E0477]: the type `Wrapper<'a>` does not fulfill the required lifetime + --> $DIR/specialize_with_generalize_lifetimes.rs:31:1 + | +LL | impl<'a> Tr for Wrapper<'a> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +note: type must satisfy the static lifetime as required by this binding + --> $DIR/specialize_with_generalize_lifetimes.rs:12:15 + | +LL | impl Tr for T { + | ^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0477`. From 0bb43c63c33bf29e7a24e696f619be8e55e62f37 Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 3 May 2023 11:46:34 +0800 Subject: [PATCH 18/26] Suggest let for possible binding with ty --- compiler/rustc_macros/src/diagnostics/mod.rs | 2 +- compiler/rustc_parse/src/parser/diagnostics.rs | 17 +++++++++++++++++ compiler/rustc_parse/src/parser/stmt.rs | 9 --------- .../type-ascription-instead-of-let.fixed | 11 +++++++++++ .../type-ascription-instead-of-let.rs | 4 +++- .../type-ascription-instead-of-let.stderr | 7 ++++++- tests/ui/type/missing-let-in-binding-2.fixed | 5 +++++ tests/ui/type/missing-let-in-binding-2.rs | 5 +++++ tests/ui/type/missing-let-in-binding-2.stderr | 13 +++++++++++++ 9 files changed, 61 insertions(+), 12 deletions(-) create mode 100644 tests/ui/suggestions/type-ascription-instead-of-let.fixed create mode 100644 tests/ui/type/missing-let-in-binding-2.fixed create mode 100644 tests/ui/type/missing-let-in-binding-2.rs create mode 100644 tests/ui/type/missing-let-in-binding-2.stderr diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs index bd84681cbb4..a536eb3b04e 100644 --- a/compiler/rustc_macros/src/diagnostics/mod.rs +++ b/compiler/rustc_macros/src/diagnostics/mod.rs @@ -140,7 +140,7 @@ pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream { /// ```fluent /// parser_expected_identifier = expected identifier /// -/// parser_expected_identifier-found = expected identifier, found {$found} +/// parser_expected_identifier_found = expected identifier, found {$found} /// /// parser_raw_identifier = escape `{$ident}` to use it as an identifier /// ``` diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 36883bd2172..e8f47346fa7 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -399,6 +399,23 @@ impl<'a> Parser<'a> { } } } + // we suggest add the missing `let` before the identifier + // `a: Ty = 1` -> `let a: Ty = 1` + if self.token == token::Colon { + let prev_span = self.prev_token.span.shrink_to_lo(); + let snapshot = self.create_snapshot_for_diagnostic(); + self.bump(); + let res = self.parse_ty(); + if res.is_ok() && self.token == token::Eq { + err.span_suggestion_verbose( + prev_span, + "you might have meant to introduce a new binding", + "let ".to_string(), + Applicability::MaybeIncorrect, + ); + } + self.restore_snapshot(snapshot); + } if let Some(recovered_ident) = recovered_ident && recover { err.emit(); diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index 1c17de337e8..ab04219b177 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -555,7 +555,6 @@ impl<'a> Parser<'a> { if self.token == token::Colon { // if next token is following a colon, it's likely a path // and we can suggest a path separator - let ident_span = self.prev_token.span; self.bump(); if self.token.span.lo() == self.prev_token.span.hi() { err.span_suggestion_verbose( @@ -565,14 +564,6 @@ impl<'a> Parser<'a> { Applicability::MaybeIncorrect, ); } - if self.look_ahead(1, |token| token == &token::Eq) { - err.span_suggestion_verbose( - ident_span.shrink_to_lo(), - "you might have meant to introduce a new binding", - "let ", - Applicability::MaybeIncorrect, - ); - } if self.sess.unstable_features.is_nightly_build() { // FIXME(Nilstrieb): Remove this again after a few months. err.note("type ascription syntax has been removed, see issue #101728 "); diff --git a/tests/ui/suggestions/type-ascription-instead-of-let.fixed b/tests/ui/suggestions/type-ascription-instead-of-let.fixed new file mode 100644 index 00000000000..e3d03b6f22a --- /dev/null +++ b/tests/ui/suggestions/type-ascription-instead-of-let.fixed @@ -0,0 +1,11 @@ +// run-rustfix + +fn fun(x: i32) -> i32 { x } + +fn main() { + let _closure_annotated = |value: i32| -> i32 { + let temp: i32 = fun(5i32); + //~^ ERROR expected identifier, found `:` + temp + value + 1 + }; +} diff --git a/tests/ui/suggestions/type-ascription-instead-of-let.rs b/tests/ui/suggestions/type-ascription-instead-of-let.rs index 5ad60243298..6e1c86f9671 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-let.rs +++ b/tests/ui/suggestions/type-ascription-instead-of-let.rs @@ -1,7 +1,9 @@ +// run-rustfix + fn fun(x: i32) -> i32 { x } fn main() { - let closure_annotated = |value: i32| -> i32 { + let _closure_annotated = |value: i32| -> i32 { temp: i32 = fun(5i32); //~^ ERROR expected identifier, found `:` temp + value + 1 diff --git a/tests/ui/suggestions/type-ascription-instead-of-let.stderr b/tests/ui/suggestions/type-ascription-instead-of-let.stderr index fb697b0ccfd..065b1f4d353 100644 --- a/tests/ui/suggestions/type-ascription-instead-of-let.stderr +++ b/tests/ui/suggestions/type-ascription-instead-of-let.stderr @@ -1,8 +1,13 @@ error: expected identifier, found `:` - --> $DIR/type-ascription-instead-of-let.rs:5:13 + --> $DIR/type-ascription-instead-of-let.rs:7:13 | LL | temp: i32 = fun(5i32); | ^ expected identifier + | +help: you might have meant to introduce a new binding + | +LL | let temp: i32 = fun(5i32); + | +++ error: aborting due to previous error diff --git a/tests/ui/type/missing-let-in-binding-2.fixed b/tests/ui/type/missing-let-in-binding-2.fixed new file mode 100644 index 00000000000..d64013c8c83 --- /dev/null +++ b/tests/ui/type/missing-let-in-binding-2.fixed @@ -0,0 +1,5 @@ +// run-rustfix + +fn main() { + let _v: Vec = vec![1, 2, 3]; //~ ERROR expected identifier, found `:` +} diff --git a/tests/ui/type/missing-let-in-binding-2.rs b/tests/ui/type/missing-let-in-binding-2.rs new file mode 100644 index 00000000000..f95f7bef215 --- /dev/null +++ b/tests/ui/type/missing-let-in-binding-2.rs @@ -0,0 +1,5 @@ +// run-rustfix + +fn main() { + _v: Vec = vec![1, 2, 3]; //~ ERROR expected identifier, found `:` +} diff --git a/tests/ui/type/missing-let-in-binding-2.stderr b/tests/ui/type/missing-let-in-binding-2.stderr new file mode 100644 index 00000000000..2e10125943e --- /dev/null +++ b/tests/ui/type/missing-let-in-binding-2.stderr @@ -0,0 +1,13 @@ +error: expected identifier, found `:` + --> $DIR/missing-let-in-binding-2.rs:4:7 + | +LL | _v: Vec = vec![1, 2, 3]; + | ^ expected identifier + | +help: you might have meant to introduce a new binding + | +LL | let _v: Vec = vec![1, 2, 3]; + | +++ + +error: aborting due to previous error + From 20e6e6a4932991c4b53605154868cfa645b04998 Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 3 May 2023 11:56:19 +0800 Subject: [PATCH 19/26] cleanup --- compiler/rustc_parse/src/parser/diagnostics.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index e8f47346fa7..bd0ea50b4d8 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -405,8 +405,7 @@ impl<'a> Parser<'a> { let prev_span = self.prev_token.span.shrink_to_lo(); let snapshot = self.create_snapshot_for_diagnostic(); self.bump(); - let res = self.parse_ty(); - if res.is_ok() && self.token == token::Eq { + if self.parse_ty().is_ok() && self.token == token::Eq { err.span_suggestion_verbose( prev_span, "you might have meant to introduce a new binding", From a7fc32ceaf4708a26a992f61c4ac4ead1555c8eb Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 8 May 2023 11:16:17 +0800 Subject: [PATCH 20/26] fix ice in suggesting --- .../rustc_parse/src/parser/diagnostics.rs | 21 ++++++++++++------- tests/ui/type/missing-let-in-binding-3.rs | 5 +++++ tests/ui/type/missing-let-in-binding-3.stderr | 10 +++++++++ 3 files changed, 29 insertions(+), 7 deletions(-) create mode 100644 tests/ui/type/missing-let-in-binding-3.rs create mode 100644 tests/ui/type/missing-let-in-binding-3.stderr diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index bd0ea50b4d8..456c6243bbb 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -405,13 +405,20 @@ impl<'a> Parser<'a> { let prev_span = self.prev_token.span.shrink_to_lo(); let snapshot = self.create_snapshot_for_diagnostic(); self.bump(); - if self.parse_ty().is_ok() && self.token == token::Eq { - err.span_suggestion_verbose( - prev_span, - "you might have meant to introduce a new binding", - "let ".to_string(), - Applicability::MaybeIncorrect, - ); + match self.parse_ty() { + Ok(_) => { + if self.token == token::Eq { + err.span_suggestion_verbose( + prev_span, + "you might have meant to introduce a new binding", + "let ".to_string(), + Applicability::MaybeIncorrect, + ); + } + } + Err(err) => { + err.cancel(); + } } self.restore_snapshot(snapshot); } diff --git a/tests/ui/type/missing-let-in-binding-3.rs b/tests/ui/type/missing-let-in-binding-3.rs new file mode 100644 index 00000000000..d56b1393336 --- /dev/null +++ b/tests/ui/type/missing-let-in-binding-3.rs @@ -0,0 +1,5 @@ +struct A { + : :u8, //~ ERROR expected identifier, found `:` +} + +fn main() {} diff --git a/tests/ui/type/missing-let-in-binding-3.stderr b/tests/ui/type/missing-let-in-binding-3.stderr new file mode 100644 index 00000000000..ca828ce37eb --- /dev/null +++ b/tests/ui/type/missing-let-in-binding-3.stderr @@ -0,0 +1,10 @@ +error: expected identifier, found `:` + --> $DIR/missing-let-in-binding-3.rs:2:5 + | +LL | struct A { + | - while parsing this struct +LL | : :u8, + | ^ expected identifier + +error: aborting due to previous error + From a9051d861ca13a1c16da3cd4248b26d86cf5e1d5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 18 Apr 2023 19:44:27 +0000 Subject: [PATCH 21/26] Tweak borrow suggestion --- compiler/rustc_hir_typeck/src/demand.rs | 81 ++++++------ .../argument-suggestions/issue-97484.stderr | 2 +- .../ui/async-await/issues/issue-102206.stderr | 10 +- tests/ui/coercion/coercion-slice.stderr | 11 +- tests/ui/inference/deref-suggestion.stderr | 20 +-- tests/ui/issues/issue-11374.stderr | 10 +- tests/ui/issues/issue-17033.stderr | 11 +- tests/ui/issues/issue-18819.stderr | 2 +- tests/ui/issues/issue-46302.stderr | 10 +- tests/ui/issues/issue-61106.stderr | 10 +- tests/ui/methods/method-self-arg-1.stderr | 10 +- .../dont-point-return-on-E0308.stderr | 10 +- tests/ui/mut/mut-cross-borrowing.stderr | 10 +- tests/ui/range/issue-54505-no-literals.fixed | 24 ++-- tests/ui/range/issue-54505-no-literals.rs | 24 ++-- tests/ui/range/issue-54505-no-literals.stderr | 120 +++++++++++------- tests/ui/span/coerce-suggestions.stderr | 11 +- tests/ui/span/issue-39018.stderr | 10 +- tests/ui/str/str-array-assignment.stderr | 21 +-- tests/ui/suggestions/suggest-ref-macro.rs | 4 +- tests/ui/suggestions/suggest-ref-macro.stderr | 19 +-- tests/ui/type/type-mismatch.stderr | 20 +-- .../ui/typeck/bad-index-due-to-nested.stderr | 18 +-- .../ui/typeck/bad-type-in-vec-contains.stderr | 10 +- tests/ui/typeck/issue-13853.stderr | 10 +- tests/ui/unsized-locals/suggest-borrow.stderr | 11 +- 26 files changed, 288 insertions(+), 211 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index ee81ea345a6..b8de22272dd 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1334,52 +1334,55 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } - if let Ok(src) = sm.span_to_snippet(sugg_sp) { - let needs_parens = match expr.kind { - // parenthesize if needed (Issue #46756) - hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, - // parenthesize borrows of range literals (Issue #54505) - _ if is_range_literal(expr) => true, - _ => false, - }; + let needs_parens = match expr.kind { + // parenthesize if needed (Issue #46756) + hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true, + // parenthesize borrows of range literals (Issue #54505) + _ if is_range_literal(expr) => true, + _ => false, + }; - if let Some(sugg) = self.can_use_as_ref(expr) { - return Some(( - sugg.0, - sugg.1.to_string(), - sugg.2, - Applicability::MachineApplicable, - false, - false, - )); - } - - let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) { - Some(ident) => format!("{ident}: "), - None => String::new(), - }; - - if let Some(hir::Node::Expr(hir::Expr { - kind: hir::ExprKind::Assign(..), - .. - })) = self.tcx.hir().find_parent(expr.hir_id) - { - if mutability.is_mut() { - // Suppressing this diagnostic, we'll properly print it in `check_expr_assign` - return None; - } - } - - let sugg_expr = if needs_parens { format!("({src})") } else { src }; + if let Some(sugg) = self.can_use_as_ref(expr) { return Some(( - sp, - format!("consider {}borrowing here", mutability.mutably_str()), - format!("{prefix}{}{sugg_expr}", mutability.ref_prefix_str()), + sugg.0, + sugg.1.to_string(), + sugg.2, Applicability::MachineApplicable, false, false, )); } + + let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) { + Some(ident) => format!("{ident}: "), + None => String::new(), + }; + + if let Some(hir::Node::Expr(hir::Expr { + kind: hir::ExprKind::Assign(..), + .. + })) = self.tcx.hir().find_parent(expr.hir_id) + { + if mutability.is_mut() { + // Suppressing this diagnostic, we'll properly print it in `check_expr_assign` + return None; + } + } + + let (sp, sugg_expr, verbose) = if needs_parens { + let src = sm.span_to_snippet(sugg_sp).ok()?; + (sp, format!("({src})"), false) + } else { + (sp.shrink_to_lo(), "".to_string(), true) + }; + return Some(( + sp, + format!("consider {}borrowing here", mutability.mutably_str()), + format!("{prefix}{}{sugg_expr}", mutability.ref_prefix_str()), + Applicability::MachineApplicable, + verbose, + false, + )); } } ( diff --git a/tests/ui/argument-suggestions/issue-97484.stderr b/tests/ui/argument-suggestions/issue-97484.stderr index a86cbbf1802..082564fbc7f 100644 --- a/tests/ui/argument-suggestions/issue-97484.stderr +++ b/tests/ui/argument-suggestions/issue-97484.stderr @@ -16,7 +16,7 @@ LL | fn foo(a: &A, d: D, e: &E, g: G) {} help: consider borrowing here | LL | foo(&&A, B, C, D, &E, F, G); - | ~~ + | + help: remove the extra arguments | LL - foo(&&A, B, C, D, E, F, G); diff --git a/tests/ui/async-await/issues/issue-102206.stderr b/tests/ui/async-await/issues/issue-102206.stderr index 750b7a886ef..cd845056805 100644 --- a/tests/ui/async-await/issues/issue-102206.stderr +++ b/tests/ui/async-await/issues/issue-102206.stderr @@ -2,14 +2,16 @@ error[E0308]: mismatched types --> $DIR/issue-102206.rs:6:27 | LL | std::mem::size_of_val(foo()); - | --------------------- ^^^^^ - | | | - | | expected `&_`, found future - | | help: consider borrowing here: `&foo()` + | --------------------- ^^^^^ expected `&_`, found future + | | | arguments to this function are incorrect | note: function defined here --> $SRC_DIR/core/src/mem/mod.rs:LL:COL +help: consider borrowing here + | +LL | std::mem::size_of_val(&foo()); + | + error: aborting due to previous error diff --git a/tests/ui/coercion/coercion-slice.stderr b/tests/ui/coercion/coercion-slice.stderr index c7b856a57eb..17bbca7a0bd 100644 --- a/tests/ui/coercion/coercion-slice.stderr +++ b/tests/ui/coercion/coercion-slice.stderr @@ -2,11 +2,14 @@ error[E0308]: mismatched types --> $DIR/coercion-slice.rs:4:21 | LL | let _: &[i32] = [0]; - | ------ ^^^ - | | | - | | expected `&[i32]`, found `[{integer}; 1]` - | | help: consider borrowing here: `&[0]` + | ------ ^^^ expected `&[i32]`, found `[{integer}; 1]` + | | | expected due to this + | +help: consider borrowing here + | +LL | let _: &[i32] = &[0]; + | + error: aborting due to previous error diff --git a/tests/ui/inference/deref-suggestion.stderr b/tests/ui/inference/deref-suggestion.stderr index 6f5aacacfc1..c58aab42269 100644 --- a/tests/ui/inference/deref-suggestion.stderr +++ b/tests/ui/inference/deref-suggestion.stderr @@ -98,19 +98,23 @@ error[E0308]: mismatched types --> $DIR/deref-suggestion.rs:40:17 | LL | let s = S { u }; - | ^ - | | - | expected `&u32`, found integer - | help: consider borrowing here: `u: &u` + | ^ expected `&u32`, found integer + | +help: consider borrowing here + | +LL | let s = S { u: &u }; + | ++++ error[E0308]: mismatched types --> $DIR/deref-suggestion.rs:42:20 | LL | let s = S { u: u }; - | ^ - | | - | expected `&u32`, found integer - | help: consider borrowing here: `&u` + | ^ expected `&u32`, found integer + | +help: consider borrowing here + | +LL | let s = S { u: &u }; + | + error[E0308]: mismatched types --> $DIR/deref-suggestion.rs:45:17 diff --git a/tests/ui/issues/issue-11374.stderr b/tests/ui/issues/issue-11374.stderr index 6e1fb1540bb..879dc5b76c5 100644 --- a/tests/ui/issues/issue-11374.stderr +++ b/tests/ui/issues/issue-11374.stderr @@ -2,10 +2,8 @@ error[E0308]: mismatched types --> $DIR/issue-11374.rs:26:15 | LL | c.read_to(v); - | ------- ^ - | | | - | | expected `&mut [u8]`, found `Vec<_>` - | | help: consider mutably borrowing here: `&mut v` + | ------- ^ expected `&mut [u8]`, found `Vec<_>` + | | | arguments to this method are incorrect | = note: expected mutable reference `&mut [u8]` @@ -15,6 +13,10 @@ note: method defined here | LL | pub fn read_to(&mut self, vec: &mut [u8]) { | ^^^^^^^ -------------- +help: consider mutably borrowing here + | +LL | c.read_to(&mut v); + | ++++ error: aborting due to previous error diff --git a/tests/ui/issues/issue-17033.stderr b/tests/ui/issues/issue-17033.stderr index f26bee5ff45..3419c079859 100644 --- a/tests/ui/issues/issue-17033.stderr +++ b/tests/ui/issues/issue-17033.stderr @@ -2,11 +2,14 @@ error[E0308]: mismatched types --> $DIR/issue-17033.rs:2:10 | LL | (*p)(()) - | ---- ^^ - | | | - | | expected `&mut ()`, found `()` - | | help: consider mutably borrowing here: `&mut ()` + | ---- ^^ expected `&mut ()`, found `()` + | | | arguments to this function are incorrect + | +help: consider mutably borrowing here + | +LL | (*p)(&mut ()) + | ++++ error: aborting due to previous error diff --git a/tests/ui/issues/issue-18819.stderr b/tests/ui/issues/issue-18819.stderr index 1fc974b609c..40098f9622f 100644 --- a/tests/ui/issues/issue-18819.stderr +++ b/tests/ui/issues/issue-18819.stderr @@ -19,7 +19,7 @@ LL | fn print_x(_: &dyn Foo, extra: &str) { help: consider borrowing here | LL | print_x(&X); - | ~~ + | + help: provide the argument | LL | print_x(/* &dyn Foo */, /* &str */); diff --git a/tests/ui/issues/issue-46302.stderr b/tests/ui/issues/issue-46302.stderr index a6f97c3c9af..6e126038cc9 100644 --- a/tests/ui/issues/issue-46302.stderr +++ b/tests/ui/issues/issue-46302.stderr @@ -2,10 +2,12 @@ error[E0308]: mismatched types --> $DIR/issue-46302.rs:3:27 | LL | let u: &str = if true { s[..2] } else { s }; - | ^^^^^^ - | | - | expected `&str`, found `str` - | help: consider borrowing here: `&s[..2]` + | ^^^^^^ expected `&str`, found `str` + | +help: consider borrowing here + | +LL | let u: &str = if true { &s[..2] } else { s }; + | + error: aborting due to previous error diff --git a/tests/ui/issues/issue-61106.stderr b/tests/ui/issues/issue-61106.stderr index eff3e6e7849..aa922e2682d 100644 --- a/tests/ui/issues/issue-61106.stderr +++ b/tests/ui/issues/issue-61106.stderr @@ -2,10 +2,8 @@ error[E0308]: mismatched types --> $DIR/issue-61106.rs:3:9 | LL | foo(x.clone()); - | --- ^^^^^^^^^ - | | | - | | expected `&str`, found `String` - | | help: consider borrowing here: `&x` + | --- ^^^^^^^^^ expected `&str`, found `String` + | | | arguments to this function are incorrect | note: function defined here @@ -13,6 +11,10 @@ note: function defined here | LL | fn foo(_: &str) {} | ^^^ ------- +help: consider borrowing here + | +LL | foo(&x.clone()); + | + error: aborting due to previous error diff --git a/tests/ui/methods/method-self-arg-1.stderr b/tests/ui/methods/method-self-arg-1.stderr index 9241a8be58f..dcc21acc5c0 100644 --- a/tests/ui/methods/method-self-arg-1.stderr +++ b/tests/ui/methods/method-self-arg-1.stderr @@ -2,10 +2,8 @@ error[E0308]: mismatched types --> $DIR/method-self-arg-1.rs:11:14 | LL | Foo::bar(x); - | -------- ^ - | | | - | | expected `&Foo`, found `Foo` - | | help: consider borrowing here: `&x` + | -------- ^ expected `&Foo`, found `Foo` + | | | arguments to this function are incorrect | note: method defined here @@ -13,6 +11,10 @@ note: method defined here | LL | fn bar(&self) {} | ^^^ ----- +help: consider borrowing here + | +LL | Foo::bar(&x); + | + error[E0308]: mismatched types --> $DIR/method-self-arg-1.rs:13:14 diff --git a/tests/ui/mismatched_types/dont-point-return-on-E0308.stderr b/tests/ui/mismatched_types/dont-point-return-on-E0308.stderr index 13942682d28..7be94ef4ad6 100644 --- a/tests/ui/mismatched_types/dont-point-return-on-E0308.stderr +++ b/tests/ui/mismatched_types/dont-point-return-on-E0308.stderr @@ -2,10 +2,8 @@ error[E0308]: mismatched types --> $DIR/dont-point-return-on-E0308.rs:11:11 | LL | f(()); - | - ^^ - | | | - | | expected `&()`, found `()` - | | help: consider borrowing here: `&()` + | - ^^ expected `&()`, found `()` + | | | arguments to this function are incorrect | note: function defined here @@ -13,6 +11,10 @@ note: function defined here | LL | async fn f(_: &()) {} | ^ ------ +help: consider borrowing here + | +LL | f(&()); + | + error: aborting due to previous error diff --git a/tests/ui/mut/mut-cross-borrowing.stderr b/tests/ui/mut/mut-cross-borrowing.stderr index 8401827e51f..8a3076db9b2 100644 --- a/tests/ui/mut/mut-cross-borrowing.stderr +++ b/tests/ui/mut/mut-cross-borrowing.stderr @@ -2,10 +2,8 @@ error[E0308]: mismatched types --> $DIR/mut-cross-borrowing.rs:7:7 | LL | f(x) - | - ^ - | | | - | | expected `&mut isize`, found `Box<{integer}>` - | | help: consider mutably borrowing here: `&mut x` + | - ^ expected `&mut isize`, found `Box<{integer}>` + | | | arguments to this function are incorrect | = note: expected mutable reference `&mut isize` @@ -15,6 +13,10 @@ note: function defined here | LL | fn f(_: &mut isize) {} | ^ ------------- +help: consider mutably borrowing here + | +LL | f(&mut x) + | ++++ error: aborting due to previous error diff --git a/tests/ui/range/issue-54505-no-literals.fixed b/tests/ui/range/issue-54505-no-literals.fixed index 4d8f67182b9..71c36c741cc 100644 --- a/tests/ui/range/issue-54505-no-literals.fixed +++ b/tests/ui/range/issue-54505-no-literals.fixed @@ -16,60 +16,60 @@ fn main() { take_range(&std::ops::Range { start: 0, end: 1 }); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &std::ops::Range { start: 0, end: 1 } + //~| SUGGESTION & take_range(&::std::ops::Range { start: 0, end: 1 }); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &::std::ops::Range { start: 0, end: 1 } + //~| SUGGESTION & take_range(&std::ops::RangeFrom { start: 1 }); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &std::ops::RangeFrom { start: 1 } + //~| SUGGESTION & take_range(&::std::ops::RangeFrom { start: 1 }); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &::std::ops::RangeFrom { start: 1 } + //~| SUGGESTION & take_range(&std::ops::RangeFull {}); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &std::ops::RangeFull {} + //~| SUGGESTION & take_range(&::std::ops::RangeFull {}); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &::std::ops::RangeFull {} + //~| SUGGESTION & take_range(&std::ops::RangeInclusive::new(0, 1)); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &std::ops::RangeInclusive::new(0, 1) + //~| SUGGESTION & take_range(&::std::ops::RangeInclusive::new(0, 1)); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &::std::ops::RangeInclusive::new(0, 1) + //~| SUGGESTION & take_range(&std::ops::RangeTo { end: 5 }); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &std::ops::RangeTo { end: 5 } + //~| SUGGESTION & take_range(&::std::ops::RangeTo { end: 5 }); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &::std::ops::RangeTo { end: 5 } + //~| SUGGESTION & take_range(&std::ops::RangeToInclusive { end: 5 }); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &std::ops::RangeToInclusive { end: 5 } + //~| SUGGESTION & take_range(&::std::ops::RangeToInclusive { end: 5 }); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &::std::ops::RangeToInclusive { end: 5 } + //~| SUGGESTION & } diff --git a/tests/ui/range/issue-54505-no-literals.rs b/tests/ui/range/issue-54505-no-literals.rs index dc21dcbc2db..db125d1a22b 100644 --- a/tests/ui/range/issue-54505-no-literals.rs +++ b/tests/ui/range/issue-54505-no-literals.rs @@ -16,60 +16,60 @@ fn main() { take_range(std::ops::Range { start: 0, end: 1 }); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &std::ops::Range { start: 0, end: 1 } + //~| SUGGESTION & take_range(::std::ops::Range { start: 0, end: 1 }); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &::std::ops::Range { start: 0, end: 1 } + //~| SUGGESTION & take_range(std::ops::RangeFrom { start: 1 }); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &std::ops::RangeFrom { start: 1 } + //~| SUGGESTION & take_range(::std::ops::RangeFrom { start: 1 }); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &::std::ops::RangeFrom { start: 1 } + //~| SUGGESTION & take_range(std::ops::RangeFull {}); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &std::ops::RangeFull {} + //~| SUGGESTION & take_range(::std::ops::RangeFull {}); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &::std::ops::RangeFull {} + //~| SUGGESTION & take_range(std::ops::RangeInclusive::new(0, 1)); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &std::ops::RangeInclusive::new(0, 1) + //~| SUGGESTION & take_range(::std::ops::RangeInclusive::new(0, 1)); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &::std::ops::RangeInclusive::new(0, 1) + //~| SUGGESTION & take_range(std::ops::RangeTo { end: 5 }); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &std::ops::RangeTo { end: 5 } + //~| SUGGESTION & take_range(::std::ops::RangeTo { end: 5 }); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &::std::ops::RangeTo { end: 5 } + //~| SUGGESTION & take_range(std::ops::RangeToInclusive { end: 5 }); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &std::ops::RangeToInclusive { end: 5 } + //~| SUGGESTION & take_range(::std::ops::RangeToInclusive { end: 5 }); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &::std::ops::RangeToInclusive { end: 5 } + //~| SUGGESTION & } diff --git a/tests/ui/range/issue-54505-no-literals.stderr b/tests/ui/range/issue-54505-no-literals.stderr index d112983848d..5894bb6ba55 100644 --- a/tests/ui/range/issue-54505-no-literals.stderr +++ b/tests/ui/range/issue-54505-no-literals.stderr @@ -2,10 +2,8 @@ error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:16:16 | LL | take_range(std::ops::Range { start: 0, end: 1 }); - | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | | - | | expected `&_`, found `Range<{integer}>` - | | help: consider borrowing here: `&std::ops::Range { start: 0, end: 1 }` + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `Range<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -15,15 +13,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&std::ops::Range { start: 0, end: 1 }); + | + error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:21:16 | LL | take_range(::std::ops::Range { start: 0, end: 1 }); - | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | | - | | expected `&_`, found `Range<{integer}>` - | | help: consider borrowing here: `&::std::ops::Range { start: 0, end: 1 }` + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `Range<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -33,15 +33,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&::std::ops::Range { start: 0, end: 1 }); + | + error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:26:16 | LL | take_range(std::ops::RangeFrom { start: 1 }); - | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | | - | | expected `&_`, found `RangeFrom<{integer}>` - | | help: consider borrowing here: `&std::ops::RangeFrom { start: 1 }` + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `RangeFrom<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -51,15 +53,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&std::ops::RangeFrom { start: 1 }); + | + error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:31:16 | LL | take_range(::std::ops::RangeFrom { start: 1 }); - | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | | - | | expected `&_`, found `RangeFrom<{integer}>` - | | help: consider borrowing here: `&::std::ops::RangeFrom { start: 1 }` + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `RangeFrom<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -69,15 +73,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&::std::ops::RangeFrom { start: 1 }); + | + error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:36:16 | LL | take_range(std::ops::RangeFull {}); - | ---------- ^^^^^^^^^^^^^^^^^^^^^^ - | | | - | | expected `&_`, found `RangeFull` - | | help: consider borrowing here: `&std::ops::RangeFull {}` + | ---------- ^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `RangeFull` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -87,15 +93,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&std::ops::RangeFull {}); + | + error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:41:16 | LL | take_range(::std::ops::RangeFull {}); - | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^ - | | | - | | expected `&_`, found `RangeFull` - | | help: consider borrowing here: `&::std::ops::RangeFull {}` + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `RangeFull` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -105,15 +113,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&::std::ops::RangeFull {}); + | + error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:46:16 | LL | take_range(std::ops::RangeInclusive::new(0, 1)); - | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | | - | | expected `&_`, found `RangeInclusive<{integer}>` - | | help: consider borrowing here: `&std::ops::RangeInclusive::new(0, 1)` + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `RangeInclusive<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -123,15 +133,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&std::ops::RangeInclusive::new(0, 1)); + | + error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:51:16 | LL | take_range(::std::ops::RangeInclusive::new(0, 1)); - | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | | - | | expected `&_`, found `RangeInclusive<{integer}>` - | | help: consider borrowing here: `&::std::ops::RangeInclusive::new(0, 1)` + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `RangeInclusive<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -141,15 +153,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&::std::ops::RangeInclusive::new(0, 1)); + | + error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:56:16 | LL | take_range(std::ops::RangeTo { end: 5 }); - | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | | - | | expected `&_`, found `RangeTo<{integer}>` - | | help: consider borrowing here: `&std::ops::RangeTo { end: 5 }` + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `RangeTo<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -159,15 +173,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&std::ops::RangeTo { end: 5 }); + | + error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:61:16 | LL | take_range(::std::ops::RangeTo { end: 5 }); - | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | | - | | expected `&_`, found `RangeTo<{integer}>` - | | help: consider borrowing here: `&::std::ops::RangeTo { end: 5 }` + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `RangeTo<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -177,15 +193,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&::std::ops::RangeTo { end: 5 }); + | + error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:66:16 | LL | take_range(std::ops::RangeToInclusive { end: 5 }); - | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | | - | | expected `&_`, found `RangeToInclusive<{integer}>` - | | help: consider borrowing here: `&std::ops::RangeToInclusive { end: 5 }` + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `RangeToInclusive<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -195,15 +213,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&std::ops::RangeToInclusive { end: 5 }); + | + error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:71:16 | LL | take_range(::std::ops::RangeToInclusive { end: 5 }); - | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | | | - | | expected `&_`, found `RangeToInclusive<{integer}>` - | | help: consider borrowing here: `&::std::ops::RangeToInclusive { end: 5 }` + | ---------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `&_`, found `RangeToInclusive<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -213,6 +233,10 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&::std::ops::RangeToInclusive { end: 5 }); + | + error: aborting due to 12 previous errors diff --git a/tests/ui/span/coerce-suggestions.stderr b/tests/ui/span/coerce-suggestions.stderr index bb30f000ea7..ff840b781f0 100644 --- a/tests/ui/span/coerce-suggestions.stderr +++ b/tests/ui/span/coerce-suggestions.stderr @@ -10,11 +10,14 @@ error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:9:19 | LL | let x: &str = String::new(); - | ---- ^^^^^^^^^^^^^ - | | | - | | expected `&str`, found `String` - | | help: consider borrowing here: `&String::new()` + | ---- ^^^^^^^^^^^^^ expected `&str`, found `String` + | | | expected due to this + | +help: consider borrowing here + | +LL | let x: &str = &String::new(); + | + error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:12:10 diff --git a/tests/ui/span/issue-39018.stderr b/tests/ui/span/issue-39018.stderr index bae93639271..c8c4a513988 100644 --- a/tests/ui/span/issue-39018.stderr +++ b/tests/ui/span/issue-39018.stderr @@ -78,10 +78,12 @@ error[E0308]: mismatched types --> $DIR/issue-39018.rs:29:17 | LL | let _ = a + b; - | ^ - | | - | expected `&str`, found `String` - | help: consider borrowing here: `&b` + | ^ expected `&str`, found `String` + | +help: consider borrowing here + | +LL | let _ = a + &b; + | + error[E0369]: cannot add `String` to `&String` --> $DIR/issue-39018.rs:30:15 diff --git a/tests/ui/str/str-array-assignment.stderr b/tests/ui/str/str-array-assignment.stderr index c23400a1d14..515cb9e12f8 100644 --- a/tests/ui/str/str-array-assignment.stderr +++ b/tests/ui/str/str-array-assignment.stderr @@ -10,10 +10,12 @@ error[E0308]: mismatched types --> $DIR/str-array-assignment.rs:5:27 | LL | let u: &str = if true { s[..2] } else { s }; - | ^^^^^^ - | | - | expected `&str`, found `str` - | help: consider borrowing here: `&s[..2]` + | ^^^^^^ expected `&str`, found `str` + | +help: consider borrowing here + | +LL | let u: &str = if true { &s[..2] } else { s }; + | + error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/str-array-assignment.rs:7:7 @@ -33,11 +35,14 @@ error[E0308]: mismatched types --> $DIR/str-array-assignment.rs:9:17 | LL | let w: &str = s[..2]; - | ---- ^^^^^^ - | | | - | | expected `&str`, found `str` - | | help: consider borrowing here: `&s[..2]` + | ---- ^^^^^^ expected `&str`, found `str` + | | | expected due to this + | +help: consider borrowing here + | +LL | let w: &str = &s[..2]; + | + error: aborting due to 4 previous errors diff --git a/tests/ui/suggestions/suggest-ref-macro.rs b/tests/ui/suggestions/suggest-ref-macro.rs index 6f780f32a14..730f5fa1b5e 100644 --- a/tests/ui/suggestions/suggest-ref-macro.rs +++ b/tests/ui/suggestions/suggest-ref-macro.rs @@ -14,7 +14,7 @@ macro_rules! bla { () => { x(123); //~^ ERROR mismatched types - //~| SUGGESTION &mut 123 + //~| SUGGESTION &mut }; ($v:expr) => { x($v) @@ -25,5 +25,5 @@ fn main() { bla!(); bla!(456); //~^ ERROR mismatched types - //~| SUGGESTION &mut 456 + //~| SUGGESTION &mut } diff --git a/tests/ui/suggestions/suggest-ref-macro.stderr b/tests/ui/suggestions/suggest-ref-macro.stderr index 17de49fbd84..08bc9e86a50 100644 --- a/tests/ui/suggestions/suggest-ref-macro.stderr +++ b/tests/ui/suggestions/suggest-ref-macro.stderr @@ -18,10 +18,8 @@ error[E0308]: mismatched types --> $DIR/suggest-ref-macro.rs:15:11 | LL | x(123); - | - ^^^ - | | | - | | expected `&mut i32`, found integer - | | help: consider mutably borrowing here: `&mut 123` + | - ^^^ expected `&mut i32`, found integer + | | | arguments to this function are incorrect ... LL | bla!(); @@ -33,6 +31,10 @@ note: function defined here LL | fn x(_: &mut i32) {} | ^ ----------- = note: this error originates in the macro `bla` (in Nightly builds, run with -Z macro-backtrace for more info) +help: consider mutably borrowing here + | +LL | x(&mut 123); + | ++++ error[E0308]: mismatched types --> $DIR/suggest-ref-macro.rs:26:10 @@ -41,16 +43,17 @@ LL | x($v) | - arguments to this function are incorrect ... LL | bla!(456); - | ^^^ - | | - | expected `&mut i32`, found integer - | help: consider mutably borrowing here: `&mut 456` + | ^^^ expected `&mut i32`, found integer | note: function defined here --> $DIR/suggest-ref-macro.rs:11:4 | LL | fn x(_: &mut i32) {} | ^ ----------- +help: consider mutably borrowing here + | +LL | bla!(&mut 456); + | ++++ error: aborting due to 3 previous errors diff --git a/tests/ui/type/type-mismatch.stderr b/tests/ui/type/type-mismatch.stderr index 67a1f893050..ce6f29d354f 100644 --- a/tests/ui/type/type-mismatch.stderr +++ b/tests/ui/type/type-mismatch.stderr @@ -378,10 +378,8 @@ error[E0308]: mismatched types --> $DIR/type-mismatch.rs:47:23 | LL | want::<&Foo>(f); - | ----------------- ^ - | | | - | | expected `&Foo`, found `Foo` - | | help: consider borrowing here: `&f` + | ----------------- ^ expected `&Foo`, found `Foo` + | | | arguments to this function are incorrect | = note: expected reference `&Foo` @@ -391,6 +389,10 @@ note: function defined here | LL | fn want(t: T) {} | ^^^^ ---- +help: consider borrowing here + | +LL | want::<&Foo>(&f); + | + error[E0308]: mismatched types --> $DIR/type-mismatch.rs:48:26 @@ -556,10 +558,8 @@ error[E0308]: mismatched types --> $DIR/type-mismatch.rs:61:26 | LL | want::<&Foo>(f); - | -------------------- ^ - | | | - | | expected `&Foo`, found `Foo` - | | help: consider borrowing here: `&f` + | -------------------- ^ expected `&Foo`, found `Foo` + | | | arguments to this function are incorrect | = note: expected reference `&Foo` @@ -569,6 +569,10 @@ note: function defined here | LL | fn want(t: T) {} | ^^^^ ---- +help: consider borrowing here + | +LL | want::<&Foo>(&f); + | + error[E0308]: mismatched types --> $DIR/type-mismatch.rs:65:19 diff --git a/tests/ui/typeck/bad-index-due-to-nested.stderr b/tests/ui/typeck/bad-index-due-to-nested.stderr index cdb23372c4b..f9cdb280e27 100644 --- a/tests/ui/typeck/bad-index-due-to-nested.stderr +++ b/tests/ui/typeck/bad-index-due-to-nested.stderr @@ -42,13 +42,14 @@ error[E0308]: mismatched types LL | fn index<'a, K, V>(map: &'a HashMap, k: K) -> &'a V { | - this type parameter LL | map[k] - | ^ - | | - | expected `&K`, found type parameter `K` - | help: consider borrowing here: `&k` + | ^ expected `&K`, found type parameter `K` | = note: expected reference `&K` found type parameter `K` +help: consider borrowing here + | +LL | map[&k] + | + error[E0308]: mismatched types --> $DIR/bad-index-due-to-nested.rs:20:5 @@ -56,13 +57,14 @@ error[E0308]: mismatched types LL | fn index<'a, K, V>(map: &'a HashMap, k: K) -> &'a V { | - this type parameter ----- expected `&'a V` because of return type LL | map[k] - | ^^^^^^ - | | - | expected `&V`, found type parameter `V` - | help: consider borrowing here: `&map[k]` + | ^^^^^^ expected `&V`, found type parameter `V` | = note: expected reference `&'a V` found type parameter `V` +help: consider borrowing here + | +LL | &map[k] + | + error: aborting due to 4 previous errors diff --git a/tests/ui/typeck/bad-type-in-vec-contains.stderr b/tests/ui/typeck/bad-type-in-vec-contains.stderr index 72533ab1fa3..b9b3a5fe5ec 100644 --- a/tests/ui/typeck/bad-type-in-vec-contains.stderr +++ b/tests/ui/typeck/bad-type-in-vec-contains.stderr @@ -2,16 +2,18 @@ error[E0308]: mismatched types --> $DIR/bad-type-in-vec-contains.rs:5:21 | LL | primes.contains(3); - | -------- ^ - | | | - | | expected `&_`, found integer - | | help: consider borrowing here: `&3` + | -------- ^ expected `&_`, found integer + | | | arguments to this method are incorrect | = note: expected reference `&_` found type `{integer}` note: method defined here --> $SRC_DIR/core/src/slice/mod.rs:LL:COL +help: consider borrowing here + | +LL | primes.contains(&3); + | + error: aborting due to previous error diff --git a/tests/ui/typeck/issue-13853.stderr b/tests/ui/typeck/issue-13853.stderr index 11d34f5b93b..8ecb8b68016 100644 --- a/tests/ui/typeck/issue-13853.stderr +++ b/tests/ui/typeck/issue-13853.stderr @@ -20,10 +20,8 @@ error[E0308]: mismatched types --> $DIR/issue-13853.rs:37:13 | LL | iterate(graph); - | ------- ^^^^^ - | | | - | | expected `&_`, found `Vec` - | | help: consider borrowing here: `&graph` + | ------- ^^^^^ expected `&_`, found `Vec` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -33,6 +31,10 @@ note: function defined here | LL | fn iterate>(graph: &G) { | ^^^^^^^ --------- +help: consider borrowing here + | +LL | iterate(&graph); + | + error: aborting due to 3 previous errors diff --git a/tests/ui/unsized-locals/suggest-borrow.stderr b/tests/ui/unsized-locals/suggest-borrow.stderr index d456c16de0d..8741b35cdcf 100644 --- a/tests/ui/unsized-locals/suggest-borrow.stderr +++ b/tests/ui/unsized-locals/suggest-borrow.stderr @@ -16,11 +16,14 @@ error[E0308]: mismatched types --> $DIR/suggest-borrow.rs:3:20 | LL | let x: &[u8] = vec!(1, 2, 3)[..]; - | ----- ^^^^^^^^^^^^^^^^^ - | | | - | | expected `&[u8]`, found `[{integer}]` - | | help: consider borrowing here: `&vec!(1, 2, 3)[..]` + | ----- ^^^^^^^^^^^^^^^^^ expected `&[u8]`, found `[{integer}]` + | | | expected due to this + | +help: consider borrowing here + | +LL | let x: &[u8] = &vec!(1, 2, 3)[..]; + | + error[E0308]: mismatched types --> $DIR/suggest-borrow.rs:4:19 From a283f581839e17a3be4a828c95fa9e905e878ac4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 18 Apr 2023 19:51:33 +0000 Subject: [PATCH 22/26] Rename some suggestion/note functions We really shouldn't be naming functions `fn check_*` unless they're doing *typechecking*. It's especially misleading when we're doing this inside of HIR typeck. --- compiler/rustc_hir_typeck/src/demand.rs | 16 ++++++++-------- .../rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 4 ++-- compiler/rustc_hir_typeck/src/method/suggest.rs | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index b8de22272dd..447332be899 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -86,9 +86,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.emit_type_mismatch_suggestions(err, expr, expr_ty, expected, expected_ty_expr, error); self.note_type_is_not_clone(err, expected, expr_ty, expr); self.note_internal_mutation_in_method(err, expr, Some(expected), expr_ty); - self.check_for_range_as_method_call(err, expr, expr_ty, expected); - self.check_for_binding_assigned_block_without_tail_expression(err, expr, expr_ty, expected); - self.check_wrong_return_type_due_to_generic_arg(err, expr, expr_ty); + self.suggest_method_call_on_range_literal(err, expr, expr_ty, expected); + self.suggest_return_binding_for_missing_tail_expr(err, expr, expr_ty, expected); + self.note_wrong_return_ty_due_to_generic_arg(err, expr, expr_ty); } /// Requires that the two types unify, and prints an error message if @@ -1217,7 +1217,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// In addition of this check, it also checks between references mutability state. If the /// expected is mutable but the provided isn't, maybe we could just say "Hey, try with /// `&mut`!". - pub fn check_ref( + pub fn suggest_deref_or_ref( &self, expr: &hir::Expr<'tcx>, checked_ty: Ty<'tcx>, @@ -1572,7 +1572,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None } - pub fn check_for_cast( + pub fn suggest_cast( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, @@ -1939,7 +1939,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Identify when the user has written `foo..bar()` instead of `foo.bar()`. - pub fn check_for_range_as_method_call( + pub fn suggest_method_call_on_range_literal( &self, err: &mut Diagnostic, expr: &hir::Expr<'tcx>, @@ -2008,7 +2008,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Identify when the type error is because `()` is found in a binding that was assigned a /// block without a tail expression. - fn check_for_binding_assigned_block_without_tail_expression( + fn suggest_return_binding_for_missing_tail_expr( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, @@ -2050,7 +2050,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn check_wrong_return_type_due_to_generic_arg( + fn note_wrong_return_ty_due_to_generic_arg( &self, err: &mut Diagnostic, expr: &hir::Expr<'_>, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 8978139119c..8818a67934b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -275,7 +275,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> bool { let expr = expr.peel_blocks(); if let Some((sp, msg, suggestion, applicability, verbose, annotation)) = - self.check_ref(expr, found, expected) + self.suggest_deref_or_ref(expr, found, expected) { if verbose { err.span_suggestion_verbose(sp, msg, suggestion, applicability); @@ -342,7 +342,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_label(sp, format!("{descr} `{name}` defined here")); } return true; - } else if self.check_for_cast(err, expr, found, expected, expected_ty_expr) { + } else if self.suggest_cast(err, expr, found, expected, expected_ty_expr) { return true; } else { let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id); diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 30f0978d190..90653bcba70 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -1045,7 +1045,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } - self.check_for_inner_self(&mut err, source, rcvr_ty, item_name); + self.suggest_unwrapping_inner_self(&mut err, source, rcvr_ty, item_name); bound_spans.sort(); bound_spans.dedup(); @@ -1132,7 +1132,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - self.check_for_deref_method(&mut err, source, rcvr_ty, item_name, expected); + self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected); return Some(err); } @@ -1805,7 +1805,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn check_for_inner_self( + fn suggest_unwrapping_inner_self( &self, err: &mut Diagnostic, source: SelfSource<'tcx>, @@ -2175,7 +2175,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn check_for_deref_method( + fn note_derefed_ty_has_method( &self, err: &mut Diagnostic, self_source: SelfSource<'tcx>, From 4731a25d2dbe84e711101f2cbb83b40fa96c7014 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Tue, 18 Apr 2023 23:45:49 +0000 Subject: [PATCH 23/26] Make suggest_deref_or_ref return a multipart suggestion --- compiler/rustc_hir_typeck/src/demand.rs | 121 +++++++++--------- .../src/fn_ctxt/suggestions.rs | 6 +- ...-consider-borrowing-cast-or-binexpr.stderr | 20 +-- tests/ui/range/issue-54505-no-std.rs | 12 +- tests/ui/range/issue-54505-no-std.stderr | 60 +++++---- tests/ui/range/issue-54505.fixed | 12 +- tests/ui/range/issue-54505.rs | 12 +- tests/ui/range/issue-54505.stderr | 60 +++++---- ...issue-73553-misinterp-range-literal.stderr | 20 +-- tests/ui/suggestions/as-ref.stderr | 88 ++++++++----- 10 files changed, 235 insertions(+), 176 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 447332be899..51cdf64c6b9 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -1087,7 +1087,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// ```ignore (illustrative) /// opt.map(|param| { takes_ref(param) }); /// ``` - fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Span, &'static str, String)> { + fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Vec<(Span, String)>, &'static str)> { let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind else { return None; }; @@ -1133,12 +1133,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } _ => false, }; - match (is_as_ref_able, self.sess().source_map().span_to_snippet(method_path.ident.span)) { - (true, Ok(src)) => { - let suggestion = format!("as_ref().{}", src); - Some((method_path.ident.span, "consider using `as_ref` instead", suggestion)) - } - _ => None, + if is_as_ref_able { + Some(( + vec![(method_path.ident.span.shrink_to_lo(), "as_ref().".to_string())], + "consider using `as_ref` instead", + )) + } else { + None } } @@ -1223,8 +1224,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { checked_ty: Ty<'tcx>, expected: Ty<'tcx>, ) -> Option<( - Span, - String, + Vec<(Span, String)>, String, Applicability, bool, /* verbose */ @@ -1254,30 +1254,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && let Ok(src) = sm.span_to_snippet(sp) && replace_prefix(&src, "b\"", "\"").is_some() { - let pos = sp.lo() + BytePos(1); - return Some(( - sp.with_hi(pos), - "consider removing the leading `b`".to_string(), - String::new(), - Applicability::MachineApplicable, - true, - false, - )); - } - } + let pos = sp.lo() + BytePos(1); + return Some(( + vec![(sp.with_hi(pos), String::new())], + "consider removing the leading `b`".to_string(), + Applicability::MachineApplicable, + true, + false, + )); + } + } (&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => { if let hir::ExprKind::Lit(_) = expr.kind && let Ok(src) = sm.span_to_snippet(sp) && replace_prefix(&src, "\"", "b\"").is_some() { - return Some(( - sp.shrink_to_lo(), - "consider adding a leading `b`".to_string(), - "b".to_string(), - Applicability::MachineApplicable, - true, - false, - )); + return Some(( + vec![(sp.shrink_to_lo(), "b".to_string())], + "consider adding a leading `b`".to_string(), + Applicability::MachineApplicable, + true, + false, + )); } } _ => {} @@ -1320,14 +1318,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner) = expr.kind - && let Some(1) = self.deref_steps(expected, checked_ty) { + && let Some(1) = self.deref_steps(expected, checked_ty) + { // We have `*&T`, check if what was expected was `&T`. // If so, we may want to suggest removing a `*`. sugg_sp = sugg_sp.with_hi(inner.span.lo()); return Some(( - sugg_sp, + vec![(sugg_sp, String::new())], "consider removing deref here".to_string(), - "".to_string(), Applicability::MachineApplicable, true, false, @@ -1342,13 +1340,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => false, }; - if let Some(sugg) = self.can_use_as_ref(expr) { + if let Some((sugg, msg)) = self.can_use_as_ref(expr) { return Some(( - sugg.0, - sugg.1.to_string(), - sugg.2, + sugg, + msg.to_string(), Applicability::MachineApplicable, - false, + true, false, )); } @@ -1369,16 +1366,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - let (sp, sugg_expr, verbose) = if needs_parens { - let src = sm.span_to_snippet(sugg_sp).ok()?; - (sp, format!("({src})"), false) + let sugg = mutability.ref_prefix_str(); + let (sugg, verbose) = if needs_parens { + ( + vec![ + (sp.shrink_to_lo(), format!("{prefix}{sugg}(")), + (sp.shrink_to_hi(), ")".to_string()), + ], + false, + ) } else { - (sp.shrink_to_lo(), "".to_string(), true) + (vec![(sp.shrink_to_lo(), format!("{prefix}{sugg}"))], true) }; return Some(( - sp, + sugg, format!("consider {}borrowing here", mutability.mutably_str()), - format!("{prefix}{}{sugg_expr}", mutability.ref_prefix_str()), Applicability::MachineApplicable, verbose, false, @@ -1404,23 +1406,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { && sm.is_span_accessible(call_span) { return Some(( - sp.with_hi(call_span.lo()), + vec![(sp.with_hi(call_span.lo()), String::new())], "consider removing the borrow".to_string(), - String::new(), Applicability::MachineApplicable, true, - true + true, )); } return None; } - if sp.contains(expr.span) - && sm.is_span_accessible(expr.span) - { + if sp.contains(expr.span) && sm.is_span_accessible(expr.span) { return Some(( - sp.with_hi(expr.span.lo()), + vec![(sp.with_hi(expr.span.lo()), String::new())], "consider removing the borrow".to_string(), - String::new(), Applicability::MachineApplicable, true, true, @@ -1444,23 +1442,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let suggestion = replace_prefix(&src, old_prefix, &new_prefix).map(|_| { // skip `&` or `&mut ` if both mutabilities are mutable - let lo = sp.lo() + BytePos(min(old_prefix.len(), mutbl_b.ref_prefix_str().len()) as _); + let lo = sp.lo() + + BytePos(min(old_prefix.len(), mutbl_b.ref_prefix_str().len()) as _); // skip `&` or `&mut ` let hi = sp.lo() + BytePos(old_prefix.len() as _); let sp = sp.with_lo(lo).with_hi(hi); ( sp, - format!("{}{derefs}", if mutbl_a != mutbl_b { mutbl_b.prefix_str() } else { "" }), - if mutbl_b <= mutbl_a { Applicability::MachineApplicable } else { Applicability::MaybeIncorrect } + format!( + "{}{derefs}", + if mutbl_a != mutbl_b { mutbl_b.prefix_str() } else { "" } + ), + if mutbl_b <= mutbl_a { + Applicability::MachineApplicable + } else { + Applicability::MaybeIncorrect + }, ) }); if let Some((span, src, applicability)) = suggestion { return Some(( - span, + vec![(span, src)], "consider dereferencing".to_string(), - src, applicability, true, false, @@ -1489,9 +1494,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // If we've reached our target type with just removing `&`, then just print now. if steps == 0 && !remove.trim().is_empty() { return Some(( - prefix_span, + vec![(prefix_span, String::new())], format!("consider removing the `{}`", remove.trim()), - String::new(), // Do not remove `&&` to get to bool, because it might be something like // { a } && b, which we have a separate fixup suggestion that is more // likely correct... @@ -1557,9 +1561,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } return Some(( - span, + vec![(span, suggestion)], message, - suggestion, Applicability::MachineApplicable, true, false, diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 8818a67934b..aea0e4a6b2b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -274,13 +274,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>, ) -> bool { let expr = expr.peel_blocks(); - if let Some((sp, msg, suggestion, applicability, verbose, annotation)) = + if let Some((suggestion, msg, applicability, verbose, annotation)) = self.suggest_deref_or_ref(expr, found, expected) { if verbose { - err.span_suggestion_verbose(sp, msg, suggestion, applicability); + err.multipart_suggestion_verbose(msg, suggestion, applicability); } else { - err.span_suggestion(sp, msg, suggestion, applicability); + err.multipart_suggestion(msg, suggestion, applicability); } if annotation { let suggest_annotation = match expr.peel_drop_temps().kind { diff --git a/tests/ui/issues/issue-46756-consider-borrowing-cast-or-binexpr.stderr b/tests/ui/issues/issue-46756-consider-borrowing-cast-or-binexpr.stderr index e874ded8ec5..211dd512895 100644 --- a/tests/ui/issues/issue-46756-consider-borrowing-cast-or-binexpr.stderr +++ b/tests/ui/issues/issue-46756-consider-borrowing-cast-or-binexpr.stderr @@ -2,10 +2,8 @@ error[E0308]: mismatched types --> $DIR/issue-46756-consider-borrowing-cast-or-binexpr.rs:12:42 | LL | light_flows_our_war_of_mocking_words(behold as usize); - | ------------------------------------ ^^^^^^^^^^^^^^^ - | | | - | | expected `&usize`, found `usize` - | | help: consider borrowing here: `&(behold as usize)` + | ------------------------------------ ^^^^^^^^^^^^^^^ expected `&usize`, found `usize` + | | | arguments to this function are incorrect | note: function defined here @@ -13,15 +11,17 @@ note: function defined here | LL | fn light_flows_our_war_of_mocking_words(and_yet: &usize) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- +help: consider borrowing here + | +LL | light_flows_our_war_of_mocking_words(&(behold as usize)); + | ++ + error[E0308]: mismatched types --> $DIR/issue-46756-consider-borrowing-cast-or-binexpr.rs:14:42 | LL | light_flows_our_war_of_mocking_words(with_tears + 4); - | ------------------------------------ ^^^^^^^^^^^^^^ - | | | - | | expected `&usize`, found `usize` - | | help: consider borrowing here: `&(with_tears + 4)` + | ------------------------------------ ^^^^^^^^^^^^^^ expected `&usize`, found `usize` + | | | arguments to this function are incorrect | note: function defined here @@ -29,6 +29,10 @@ note: function defined here | LL | fn light_flows_our_war_of_mocking_words(and_yet: &usize) -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ --------------- +help: consider borrowing here + | +LL | light_flows_our_war_of_mocking_words(&(with_tears + 4)); + | ++ + error: aborting due to 2 previous errors diff --git a/tests/ui/range/issue-54505-no-std.rs b/tests/ui/range/issue-54505-no-std.rs index 9f378b4836e..db455fada3b 100644 --- a/tests/ui/range/issue-54505-no-std.rs +++ b/tests/ui/range/issue-54505-no-std.rs @@ -29,30 +29,30 @@ fn main() { take_range(0..1); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &(0..1) + //~| SUGGESTION &( take_range(1..); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &(1..) + //~| SUGGESTION &( take_range(..); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &(..) + //~| SUGGESTION &( take_range(0..=1); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &(0..=1) + //~| SUGGESTION &( take_range(..5); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &(..5) + //~| SUGGESTION &( take_range(..=42); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &(..=42) + //~| SUGGESTION &( } diff --git a/tests/ui/range/issue-54505-no-std.stderr b/tests/ui/range/issue-54505-no-std.stderr index a6a9f89da74..13563d1940c 100644 --- a/tests/ui/range/issue-54505-no-std.stderr +++ b/tests/ui/range/issue-54505-no-std.stderr @@ -14,10 +14,8 @@ error[E0308]: mismatched types --> $DIR/issue-54505-no-std.rs:29:16 | LL | take_range(0..1); - | ---------- ^^^^ - | | | - | | expected `&_`, found `Range<{integer}>` - | | help: consider borrowing here: `&(0..1)` + | ---------- ^^^^ expected `&_`, found `Range<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -27,15 +25,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&(0..1)); + | ++ + error[E0308]: mismatched types --> $DIR/issue-54505-no-std.rs:34:16 | LL | take_range(1..); - | ---------- ^^^ - | | | - | | expected `&_`, found `RangeFrom<{integer}>` - | | help: consider borrowing here: `&(1..)` + | ---------- ^^^ expected `&_`, found `RangeFrom<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -45,15 +45,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&(1..)); + | ++ + error[E0308]: mismatched types --> $DIR/issue-54505-no-std.rs:39:16 | LL | take_range(..); - | ---------- ^^ - | | | - | | expected `&_`, found `RangeFull` - | | help: consider borrowing here: `&(..)` + | ---------- ^^ expected `&_`, found `RangeFull` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -63,15 +65,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&(..)); + | ++ + error[E0308]: mismatched types --> $DIR/issue-54505-no-std.rs:44:16 | LL | take_range(0..=1); - | ---------- ^^^^^ - | | | - | | expected `&_`, found `RangeInclusive<{integer}>` - | | help: consider borrowing here: `&(0..=1)` + | ---------- ^^^^^ expected `&_`, found `RangeInclusive<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -81,15 +85,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&(0..=1)); + | ++ + error[E0308]: mismatched types --> $DIR/issue-54505-no-std.rs:49:16 | LL | take_range(..5); - | ---------- ^^^ - | | | - | | expected `&_`, found `RangeTo<{integer}>` - | | help: consider borrowing here: `&(..5)` + | ---------- ^^^ expected `&_`, found `RangeTo<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -99,15 +105,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&(..5)); + | ++ + error[E0308]: mismatched types --> $DIR/issue-54505-no-std.rs:54:16 | LL | take_range(..=42); - | ---------- ^^^^^ - | | | - | | expected `&_`, found `RangeToInclusive<{integer}>` - | | help: consider borrowing here: `&(..=42)` + | ---------- ^^^^^ expected `&_`, found `RangeToInclusive<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -117,6 +125,10 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&(..=42)); + | ++ + error: aborting due to 8 previous errors diff --git a/tests/ui/range/issue-54505.fixed b/tests/ui/range/issue-54505.fixed index f8298c0b5ce..9d113ba1d35 100644 --- a/tests/ui/range/issue-54505.fixed +++ b/tests/ui/range/issue-54505.fixed @@ -14,30 +14,30 @@ fn main() { take_range(&(0..1)); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &(0..1) + //~| SUGGESTION &( take_range(&(1..)); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &(1..) + //~| SUGGESTION &( take_range(&(..)); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &(..) + //~| SUGGESTION &( take_range(&(0..=1)); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &(0..=1) + //~| SUGGESTION &( take_range(&(..5)); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &(..5) + //~| SUGGESTION &( take_range(&(..=42)); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &(..=42) + //~| SUGGESTION &( } diff --git a/tests/ui/range/issue-54505.rs b/tests/ui/range/issue-54505.rs index 03673252dd3..c9929988fe5 100644 --- a/tests/ui/range/issue-54505.rs +++ b/tests/ui/range/issue-54505.rs @@ -14,30 +14,30 @@ fn main() { take_range(0..1); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &(0..1) + //~| SUGGESTION &( take_range(1..); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &(1..) + //~| SUGGESTION &( take_range(..); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &(..) + //~| SUGGESTION &( take_range(0..=1); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &(0..=1) + //~| SUGGESTION &( take_range(..5); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &(..5) + //~| SUGGESTION &( take_range(..=42); //~^ ERROR mismatched types [E0308] //~| HELP consider borrowing here - //~| SUGGESTION &(..=42) + //~| SUGGESTION &( } diff --git a/tests/ui/range/issue-54505.stderr b/tests/ui/range/issue-54505.stderr index eda047b507a..0e959fc05e2 100644 --- a/tests/ui/range/issue-54505.stderr +++ b/tests/ui/range/issue-54505.stderr @@ -2,10 +2,8 @@ error[E0308]: mismatched types --> $DIR/issue-54505.rs:14:16 | LL | take_range(0..1); - | ---------- ^^^^ - | | | - | | expected `&_`, found `Range<{integer}>` - | | help: consider borrowing here: `&(0..1)` + | ---------- ^^^^ expected `&_`, found `Range<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -15,15 +13,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&(0..1)); + | ++ + error[E0308]: mismatched types --> $DIR/issue-54505.rs:19:16 | LL | take_range(1..); - | ---------- ^^^ - | | | - | | expected `&_`, found `RangeFrom<{integer}>` - | | help: consider borrowing here: `&(1..)` + | ---------- ^^^ expected `&_`, found `RangeFrom<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -33,15 +33,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&(1..)); + | ++ + error[E0308]: mismatched types --> $DIR/issue-54505.rs:24:16 | LL | take_range(..); - | ---------- ^^ - | | | - | | expected `&_`, found `RangeFull` - | | help: consider borrowing here: `&(..)` + | ---------- ^^ expected `&_`, found `RangeFull` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -51,15 +53,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&(..)); + | ++ + error[E0308]: mismatched types --> $DIR/issue-54505.rs:29:16 | LL | take_range(0..=1); - | ---------- ^^^^^ - | | | - | | expected `&_`, found `RangeInclusive<{integer}>` - | | help: consider borrowing here: `&(0..=1)` + | ---------- ^^^^^ expected `&_`, found `RangeInclusive<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -69,15 +73,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&(0..=1)); + | ++ + error[E0308]: mismatched types --> $DIR/issue-54505.rs:34:16 | LL | take_range(..5); - | ---------- ^^^ - | | | - | | expected `&_`, found `RangeTo<{integer}>` - | | help: consider borrowing here: `&(..5)` + | ---------- ^^^ expected `&_`, found `RangeTo<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -87,15 +93,17 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&(..5)); + | ++ + error[E0308]: mismatched types --> $DIR/issue-54505.rs:39:16 | LL | take_range(..=42); - | ---------- ^^^^^ - | | | - | | expected `&_`, found `RangeToInclusive<{integer}>` - | | help: consider borrowing here: `&(..=42)` + | ---------- ^^^^^ expected `&_`, found `RangeToInclusive<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&_` @@ -105,6 +113,10 @@ note: function defined here | LL | fn take_range(_r: &impl RangeBounds) {} | ^^^^^^^^^^ ------------------------- +help: consider borrowing here + | +LL | take_range(&(..=42)); + | ++ + error: aborting due to 6 previous errors diff --git a/tests/ui/range/issue-73553-misinterp-range-literal.stderr b/tests/ui/range/issue-73553-misinterp-range-literal.stderr index 77595b3678e..52efa241d0b 100644 --- a/tests/ui/range/issue-73553-misinterp-range-literal.stderr +++ b/tests/ui/range/issue-73553-misinterp-range-literal.stderr @@ -2,10 +2,8 @@ error[E0308]: mismatched types --> $DIR/issue-73553-misinterp-range-literal.rs:12:10 | LL | demo(tell(1)..tell(10)); - | ---- ^^^^^^^^^^^^^^^^^ - | | | - | | expected `&Range`, found `Range` - | | help: consider borrowing here: `&(tell(1)..tell(10))` + | ---- ^^^^^^^^^^^^^^^^^ expected `&Range`, found `Range` + | | | arguments to this function are incorrect | = note: expected reference `&std::ops::Range` @@ -15,15 +13,17 @@ note: function defined here | LL | fn demo(r: &Range) { | ^^^^ --------- +help: consider borrowing here + | +LL | demo(&(tell(1)..tell(10))); + | ++ + error[E0308]: mismatched types --> $DIR/issue-73553-misinterp-range-literal.rs:14:10 | LL | demo(1..10); - | ---- ^^^^^ - | | | - | | expected `&Range`, found `Range<{integer}>` - | | help: consider borrowing here: `&(1..10)` + | ---- ^^^^^ expected `&Range`, found `Range<{integer}>` + | | | arguments to this function are incorrect | = note: expected reference `&std::ops::Range` @@ -33,6 +33,10 @@ note: function defined here | LL | fn demo(r: &Range) { | ^^^^ --------- +help: consider borrowing here + | +LL | demo(&(1..10)); + | ++ + error: aborting due to 2 previous errors diff --git a/tests/ui/suggestions/as-ref.stderr b/tests/ui/suggestions/as-ref.stderr index 0ee343ebf9f..2147d2d92e3 100644 --- a/tests/ui/suggestions/as-ref.stderr +++ b/tests/ui/suggestions/as-ref.stderr @@ -2,61 +2,73 @@ error[E0308]: mismatched types --> $DIR/as-ref.rs:7:29 | LL | opt.map(|arg| takes_ref(arg)); - | --- --------- ^^^ expected `&Foo`, found `Foo` - | | | - | | arguments to this function are incorrect - | help: consider using `as_ref` instead: `as_ref().map` + | --------- ^^^ expected `&Foo`, found `Foo` + | | + | arguments to this function are incorrect | note: function defined here --> $DIR/as-ref.rs:3:4 | LL | fn takes_ref(_: &Foo) {} | ^^^^^^^^^ ------- +help: consider using `as_ref` instead + | +LL | opt.as_ref().map(|arg| takes_ref(arg)); + | +++++++++ error[E0308]: mismatched types --> $DIR/as-ref.rs:8:39 | LL | opt.and_then(|arg| Some(takes_ref(arg))); - | -------- --------- ^^^ expected `&Foo`, found `Foo` - | | | - | | arguments to this function are incorrect - | help: consider using `as_ref` instead: `as_ref().and_then` + | --------- ^^^ expected `&Foo`, found `Foo` + | | + | arguments to this function are incorrect | note: function defined here --> $DIR/as-ref.rs:3:4 | LL | fn takes_ref(_: &Foo) {} | ^^^^^^^^^ ------- +help: consider using `as_ref` instead + | +LL | opt.as_ref().and_then(|arg| Some(takes_ref(arg))); + | +++++++++ error[E0308]: mismatched types --> $DIR/as-ref.rs:10:29 | LL | opt.map(|arg| takes_ref(arg)); - | --- --------- ^^^ expected `&Foo`, found `Foo` - | | | - | | arguments to this function are incorrect - | help: consider using `as_ref` instead: `as_ref().map` + | --------- ^^^ expected `&Foo`, found `Foo` + | | + | arguments to this function are incorrect | note: function defined here --> $DIR/as-ref.rs:3:4 | LL | fn takes_ref(_: &Foo) {} | ^^^^^^^^^ ------- +help: consider using `as_ref` instead + | +LL | opt.as_ref().map(|arg| takes_ref(arg)); + | +++++++++ error[E0308]: mismatched types --> $DIR/as-ref.rs:11:37 | LL | opt.and_then(|arg| Ok(takes_ref(arg))); - | -------- --------- ^^^ expected `&Foo`, found `Foo` - | | | - | | arguments to this function are incorrect - | help: consider using `as_ref` instead: `as_ref().and_then` + | --------- ^^^ expected `&Foo`, found `Foo` + | | + | arguments to this function are incorrect | note: function defined here --> $DIR/as-ref.rs:3:4 | LL | fn takes_ref(_: &Foo) {} | ^^^^^^^^^ ------- +help: consider using `as_ref` instead + | +LL | opt.as_ref().and_then(|arg| Ok(takes_ref(arg))); + | +++++++++ error[E0308]: mismatched types --> $DIR/as-ref.rs:13:29 @@ -101,61 +113,73 @@ error[E0308]: mismatched types --> $DIR/as-ref.rs:22:42 | LL | multiple_ref_opt.map(|arg| takes_ref(arg)); - | --- --------- ^^^ expected `&Foo`, found `Foo` - | | | - | | arguments to this function are incorrect - | help: consider using `as_ref` instead: `as_ref().map` + | --------- ^^^ expected `&Foo`, found `Foo` + | | + | arguments to this function are incorrect | note: function defined here --> $DIR/as-ref.rs:3:4 | LL | fn takes_ref(_: &Foo) {} | ^^^^^^^^^ ------- +help: consider using `as_ref` instead + | +LL | multiple_ref_opt.as_ref().map(|arg| takes_ref(arg)); + | +++++++++ error[E0308]: mismatched types --> $DIR/as-ref.rs:23:52 | LL | multiple_ref_opt.and_then(|arg| Some(takes_ref(arg))); - | -------- --------- ^^^ expected `&Foo`, found `Foo` - | | | - | | arguments to this function are incorrect - | help: consider using `as_ref` instead: `as_ref().and_then` + | --------- ^^^ expected `&Foo`, found `Foo` + | | + | arguments to this function are incorrect | note: function defined here --> $DIR/as-ref.rs:3:4 | LL | fn takes_ref(_: &Foo) {} | ^^^^^^^^^ ------- +help: consider using `as_ref` instead + | +LL | multiple_ref_opt.as_ref().and_then(|arg| Some(takes_ref(arg))); + | +++++++++ error[E0308]: mismatched types --> $DIR/as-ref.rs:25:45 | LL | multiple_ref_result.map(|arg| takes_ref(arg)); - | --- --------- ^^^ expected `&Foo`, found `Foo` - | | | - | | arguments to this function are incorrect - | help: consider using `as_ref` instead: `as_ref().map` + | --------- ^^^ expected `&Foo`, found `Foo` + | | + | arguments to this function are incorrect | note: function defined here --> $DIR/as-ref.rs:3:4 | LL | fn takes_ref(_: &Foo) {} | ^^^^^^^^^ ------- +help: consider using `as_ref` instead + | +LL | multiple_ref_result.as_ref().map(|arg| takes_ref(arg)); + | +++++++++ error[E0308]: mismatched types --> $DIR/as-ref.rs:26:53 | LL | multiple_ref_result.and_then(|arg| Ok(takes_ref(arg))); - | -------- --------- ^^^ expected `&Foo`, found `Foo` - | | | - | | arguments to this function are incorrect - | help: consider using `as_ref` instead: `as_ref().and_then` + | --------- ^^^ expected `&Foo`, found `Foo` + | | + | arguments to this function are incorrect | note: function defined here --> $DIR/as-ref.rs:3:4 | LL | fn takes_ref(_: &Foo) {} | ^^^^^^^^^ ------- +help: consider using `as_ref` instead + | +LL | multiple_ref_result.as_ref().and_then(|arg| Ok(takes_ref(arg))); + | +++++++++ error: aborting due to 11 previous errors From 5e94b5faf1f0812207a9128e2754bd146210b16e Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 8 May 2023 14:52:52 +0800 Subject: [PATCH 24/26] code refactor and fix wrong suggestion --- .../rustc_parse/src/parser/diagnostics.rs | 52 +++++++++++-------- compiler/rustc_parse/src/parser/stmt.rs | 8 ++- tests/ui/type/missing-let-in-binding-4.rs | 5 ++ tests/ui/type/missing-let-in-binding-4.stderr | 10 ++++ 4 files changed, 51 insertions(+), 24 deletions(-) create mode 100644 tests/ui/type/missing-let-in-binding-4.rs create mode 100644 tests/ui/type/missing-let-in-binding-4.stderr diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 456c6243bbb..b0822fe7956 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -399,29 +399,6 @@ impl<'a> Parser<'a> { } } } - // we suggest add the missing `let` before the identifier - // `a: Ty = 1` -> `let a: Ty = 1` - if self.token == token::Colon { - let prev_span = self.prev_token.span.shrink_to_lo(); - let snapshot = self.create_snapshot_for_diagnostic(); - self.bump(); - match self.parse_ty() { - Ok(_) => { - if self.token == token::Eq { - err.span_suggestion_verbose( - prev_span, - "you might have meant to introduce a new binding", - "let ".to_string(), - Applicability::MaybeIncorrect, - ); - } - } - Err(err) => { - err.cancel(); - } - } - self.restore_snapshot(snapshot); - } if let Some(recovered_ident) = recovered_ident && recover { err.emit(); @@ -1029,6 +1006,35 @@ impl<'a> Parser<'a> { Err(e) } + /// Suggest add the missing `let` before the identifier in stmt + /// `a: Ty = 1` -> `let a: Ty = 1` + pub(super) fn suggest_add_missing_let_for_stmt( + &mut self, + err: &mut DiagnosticBuilder<'a, ErrorGuaranteed>, + ) { + if self.token == token::Colon { + let prev_span = self.prev_token.span.shrink_to_lo(); + let snapshot = self.create_snapshot_for_diagnostic(); + self.bump(); + match self.parse_ty() { + Ok(_) => { + if self.token == token::Eq { + err.span_suggestion_verbose( + prev_span, + "you might have meant to introduce a new binding", + "let ".to_string(), + Applicability::MaybeIncorrect, + ); + } + } + Err(e) => { + e.cancel(); + } + } + self.restore_snapshot(snapshot); + } + } + /// Check to see if a pair of chained operators looks like an attempt at chained comparison, /// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or /// parenthesising the leftmost comparison. diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs index ab04219b177..c35c32f272a 100644 --- a/compiler/rustc_parse/src/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -99,7 +99,13 @@ impl<'a> Parser<'a> { ForceCollect::Yes => { self.collect_tokens_no_attrs(|this| this.parse_stmt_path_start(lo, attrs))? } - ForceCollect::No => self.parse_stmt_path_start(lo, attrs)?, + ForceCollect::No => match self.parse_stmt_path_start(lo, attrs) { + Ok(stmt) => stmt, + Err(mut err) => { + self.suggest_add_missing_let_for_stmt(&mut err); + return Err(err); + } + }, } } else if let Some(item) = self.parse_item_common( attrs.clone(), diff --git a/tests/ui/type/missing-let-in-binding-4.rs b/tests/ui/type/missing-let-in-binding-4.rs new file mode 100644 index 00000000000..879a6fedcd6 --- /dev/null +++ b/tests/ui/type/missing-let-in-binding-4.rs @@ -0,0 +1,5 @@ +struct A { + : u8 =, //~ ERROR expected identifier, found `:` +} + +fn main() {} diff --git a/tests/ui/type/missing-let-in-binding-4.stderr b/tests/ui/type/missing-let-in-binding-4.stderr new file mode 100644 index 00000000000..e6f173a6658 --- /dev/null +++ b/tests/ui/type/missing-let-in-binding-4.stderr @@ -0,0 +1,10 @@ +error: expected identifier, found `:` + --> $DIR/missing-let-in-binding-4.rs:2:5 + | +LL | struct A { + | - while parsing this struct +LL | : u8 =, + | ^ expected identifier + +error: aborting due to previous error + From bf7e07f627a3b183a944f90016e0e72100165e11 Mon Sep 17 00:00:00 2001 From: rustbot <47979223+rustbot@users.noreply.github.com> Date: Mon, 8 May 2023 13:00:54 -0400 Subject: [PATCH 25/26] Update books --- src/doc/edition-guide | 2 +- src/doc/embedded-book | 2 +- src/doc/reference | 2 +- src/doc/rust-by-example | 2 +- src/doc/rustc-dev-guide | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 6038be9d37d..f63e578b92f 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 6038be9d37d7251c966b486154af621d1794d7af +Subproject commit f63e578b92ff43e8cc38fcaa257b660f45c8a8c2 diff --git a/src/doc/embedded-book b/src/doc/embedded-book index 897fcf566f1..d9eb4c3f754 160000 --- a/src/doc/embedded-book +++ b/src/doc/embedded-book @@ -1 +1 @@ -Subproject commit 897fcf566f16bf87bf37199bdddec1801fd00532 +Subproject commit d9eb4c3f75435b008881062ffa77bf0d1527b37d diff --git a/src/doc/reference b/src/doc/reference index 1f8dc727e94..28dc0f3576b 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 1f8dc727e94ae4ef92adf70df979521a1ea1143e +Subproject commit 28dc0f3576b55f5e57c5d6e65cd68ba3161e9fd5 diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 31961fe2252..8ee9528b72b 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 31961fe22521a779070a44a8f30a2b00a20b6212 +Subproject commit 8ee9528b72b927cff8fd32346db8bbd1198816f0 diff --git a/src/doc/rustc-dev-guide b/src/doc/rustc-dev-guide index 2a5eb92197e..28dbeaf5c44 160000 --- a/src/doc/rustc-dev-guide +++ b/src/doc/rustc-dev-guide @@ -1 +1 @@ -Subproject commit 2a5eb92197e9cf8fe91164dcbf4f9b88c0d7e73d +Subproject commit 28dbeaf5c44bc7f5111ad412e99f2d7c5cec6c90 From 4d219d066626c49fdec3d8fa143a94c81150b633 Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 9 May 2023 11:51:04 +0800 Subject: [PATCH 26/26] move sugg to derive session diagnostic --- compiler/rustc_parse/messages.ftl | 1 + compiler/rustc_parse/src/errors.rs | 12 ++++++++++++ compiler/rustc_parse/src/parser/diagnostics.rs | 14 +++++--------- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl index cd296dca133..a01e6f5ba11 100644 --- a/compiler/rustc_parse/messages.ftl +++ b/compiler/rustc_parse/messages.ftl @@ -339,6 +339,7 @@ parse_expected_identifier = expected identifier parse_sugg_escape_identifier = escape `{$ident_name}` to use it as an identifier parse_sugg_remove_comma = remove this comma +parse_sugg_add_let_for_stmt = you might have meant to introduce a new binding parse_expected_semi_found_reserved_identifier_str = expected `;`, found reserved identifier `{$token}` parse_expected_semi_found_keyword_str = expected `;`, found keyword `{$token}` diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs index 010a13aefa4..4dffdae1dc9 100644 --- a/compiler/rustc_parse/src/errors.rs +++ b/compiler/rustc_parse/src/errors.rs @@ -906,6 +906,18 @@ pub(crate) struct SuggRemoveComma { pub span: Span, } +#[derive(Subdiagnostic)] +#[suggestion( + parse_sugg_add_let_for_stmt, + style = "verbose", + applicability = "maybe-incorrect", + code = "let " +)] +pub(crate) struct SuggAddMissingLetStmt { + #[primary_span] + pub span: Span, +} + #[derive(Subdiagnostic)] pub(crate) enum ExpectedIdentifierFound { #[label(parse_expected_identifier_found_reserved_identifier)] diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index b0822fe7956..3002f23da75 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -13,7 +13,7 @@ use crate::errors::{ IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg, PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst, StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens, - StructLiteralNeedingParensSugg, SuggEscapeIdentifier, SuggRemoveComma, + StructLiteralNeedingParensSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma, UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration, UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead, }; @@ -32,8 +32,8 @@ use rustc_ast::{ use rustc_ast_pretty::pprust; use rustc_data_structures::fx::FxHashSet; use rustc_errors::{ - pluralize, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, - FatalError, Handler, IntoDiagnostic, MultiSpan, PResult, + pluralize, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage, + ErrorGuaranteed, FatalError, Handler, IntoDiagnostic, MultiSpan, PResult, }; use rustc_session::errors::ExprParenthesesNeeded; use rustc_span::source_map::Spanned; @@ -1019,12 +1019,8 @@ impl<'a> Parser<'a> { match self.parse_ty() { Ok(_) => { if self.token == token::Eq { - err.span_suggestion_verbose( - prev_span, - "you might have meant to introduce a new binding", - "let ".to_string(), - Applicability::MaybeIncorrect, - ); + let sugg = SuggAddMissingLetStmt { span: prev_span }; + sugg.add_to_diagnostic(err); } } Err(e) => {