From 958a02247a8c4c1375220bdcf7098b1e848e28bf Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Wed, 20 Mar 2024 10:25:13 +0000
Subject: [PATCH 1/2] Use the more informative generic type inference failure
 error on method calls on raw pointers

---
 .../src/error_codes/E0699.md                  |  4 +-
 compiler/rustc_error_codes/src/lib.rs         |  2 +-
 compiler/rustc_hir_typeck/messages.ftl        |  3 --
 compiler/rustc_hir_typeck/src/errors.rs       |  7 ---
 compiler/rustc_hir_typeck/src/method/probe.rs | 43 +++++++++++--------
 src/tools/tidy/src/error_codes.rs             |  2 +-
 .../edition-raw-pointer-method-2018.rs        |  2 +-
 .../edition-raw-pointer-method-2018.stderr    | 16 +++++--
 .../ui/methods/call_method_unknown_pointee.rs |  8 ++--
 .../call_method_unknown_pointee.stderr        | 40 +++++++++++++----
 10 files changed, 79 insertions(+), 48 deletions(-)

diff --git a/compiler/rustc_error_codes/src/error_codes/E0699.md b/compiler/rustc_error_codes/src/error_codes/E0699.md
index 454d2507e5e2e..1094ebf4b8fc7 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0699.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0699.md
@@ -1,8 +1,10 @@
+#### Note: this error code is no longer emitted by the compiler.
+
 A method was called on a raw pointer whose inner type wasn't completely known.
 
 Erroneous code example:
 
-```compile_fail,edition2018,E0699
+```compile_fail,edition2018
 # #![deny(warnings)]
 # fn main() {
 let foo = &1;
diff --git a/compiler/rustc_error_codes/src/lib.rs b/compiler/rustc_error_codes/src/lib.rs
index da688e385aa09..f4a33a05c1b36 100644
--- a/compiler/rustc_error_codes/src/lib.rs
+++ b/compiler/rustc_error_codes/src/lib.rs
@@ -441,7 +441,7 @@ E0695: 0695,
 E0696: 0696,
 E0697: 0697,
 E0698: 0698,
-E0699: 0699,
+E0699: 0699, // REMOVED: merged into generic inference var error
 E0700: 0700,
 E0701: 0701,
 E0703: 0703,
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 220da19a29dc8..d4e9480eec6b6 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -93,9 +93,6 @@ hir_typeck_lossy_provenance_ptr2int =
     .suggestion = use `.addr()` to obtain the address of a pointer
     .help = if you can't comply with strict provenance and need to expose the pointer provenance you can use `.expose_addr()` instead
 
-hir_typeck_method_call_on_unknown_raw_pointee =
-    cannot call a method on a raw pointer with an unknown pointee type
-
 hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
 
 hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method ->
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index df21b84f92ef3..cabe958221f7c 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -76,13 +76,6 @@ pub struct StructExprNonExhaustive {
     pub what: &'static str,
 }
 
-#[derive(Diagnostic)]
-#[diag(hir_typeck_method_call_on_unknown_raw_pointee, code = E0699)]
-pub struct MethodCallOnUnknownRawPointee {
-    #[primary_span]
-    pub span: Span,
-}
-
 #[derive(Diagnostic)]
 #[diag(hir_typeck_functional_record_update_on_non_struct, code = E0436)]
 pub struct FunctionalRecordUpdateOnNonStruct {
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 193ea0408996c..10fb93fbeea04 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -3,7 +3,6 @@ use super::CandidateSource;
 use super::MethodError;
 use super::NoMatchData;
 
-use crate::errors::MethodCallOnUnknownRawPointee;
 use crate::FnCtxt;
 use rustc_data_structures::fx::FxHashSet;
 use rustc_errors::Applicability;
@@ -433,21 +432,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             if is_suggestion.0 {
                 // Ambiguity was encountered during a suggestion. Just keep going.
                 debug!("ProbeContext: encountered ambiguity in suggestion");
-            } else if bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types {
+            } else if bad_ty.reached_raw_pointer
+                && !self.tcx.features().arbitrary_self_types
+                && !self.tcx.sess.at_least_rust_2018()
+            {
                 // this case used to be allowed by the compiler,
                 // so we do a future-compat lint here for the 2015 edition
                 // (see https://github.com/rust-lang/rust/issues/46906)
-                if self.tcx.sess.at_least_rust_2018() {
-                    self.dcx().emit_err(MethodCallOnUnknownRawPointee { span });
-                } else {
-                    self.tcx.node_span_lint(
-                        lint::builtin::TYVAR_BEHIND_RAW_POINTER,
-                        scope_expr_id,
-                        span,
-                        "type annotations needed",
-                        |_| {},
-                    );
-                }
+                self.tcx.node_span_lint(
+                    lint::builtin::TYVAR_BEHIND_RAW_POINTER,
+                    scope_expr_id,
+                    span,
+                    "type annotations needed",
+                    |_| {},
+                );
             } else {
                 // Ended up encountering a type variable when doing autoderef,
                 // but it may not be a type variable after processing obligations
@@ -458,10 +456,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty));
                 let ty = self.resolve_vars_if_possible(ty.value);
                 let guar = match *ty.kind() {
-                    ty::Infer(ty::TyVar(_)) => self
-                        .err_ctxt()
-                        .emit_inference_failure_err(self.body_id, span, ty.into(), E0282, true)
-                        .emit(),
+                    ty::Infer(ty::TyVar(_)) => {
+                        let raw_ptr_call =
+                            bad_ty.reached_raw_pointer && !self.tcx.features().arbitrary_self_types;
+                        let mut err = self.err_ctxt().emit_inference_failure_err(
+                            self.body_id,
+                            span,
+                            ty.into(),
+                            E0282,
+                            !raw_ptr_call,
+                        );
+                        if raw_ptr_call {
+                            err.span_label(span, "cannot call a method on a raw pointer with an unknown pointee type");
+                        }
+                        err.emit()
+                    }
                     ty::Error(guar) => guar,
                     _ => bug!("unexpected bad final type in method autoderef"),
                 };
diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs
index 6fc65e56901a7..a03347fdc3b4e 100644
--- a/src/tools/tidy/src/error_codes.rs
+++ b/src/tools/tidy/src/error_codes.rs
@@ -153,7 +153,7 @@ fn check_error_codes_docs(
         if error_codes.iter().all(|e| e != err_code) {
             errors.push(format!(
                 "Found valid file `{}` in error code docs directory without corresponding \
-                entry in `error_code.rs`",
+                entry in `rustc_error_codes/src/lib.rs`",
                 path.display()
             ));
             return;
diff --git a/tests/ui/editions/edition-raw-pointer-method-2018.rs b/tests/ui/editions/edition-raw-pointer-method-2018.rs
index b346953e187ee..ad47553d5b7a2 100644
--- a/tests/ui/editions/edition-raw-pointer-method-2018.rs
+++ b/tests/ui/editions/edition-raw-pointer-method-2018.rs
@@ -6,6 +6,6 @@
 fn main() {
     let x = 0;
     let y = &x as *const _;
+    //~^ error: type annotations needed
     let _ = y.is_null();
-    //~^ error: cannot call a method on a raw pointer with an unknown pointee type [E0699]
 }
diff --git a/tests/ui/editions/edition-raw-pointer-method-2018.stderr b/tests/ui/editions/edition-raw-pointer-method-2018.stderr
index 663843ad7bc78..2792d1e740056 100644
--- a/tests/ui/editions/edition-raw-pointer-method-2018.stderr
+++ b/tests/ui/editions/edition-raw-pointer-method-2018.stderr
@@ -1,9 +1,17 @@
-error[E0699]: cannot call a method on a raw pointer with an unknown pointee type
-  --> $DIR/edition-raw-pointer-method-2018.rs:9:15
+error[E0282]: type annotations needed for `*const _`
+  --> $DIR/edition-raw-pointer-method-2018.rs:8:9
    |
+LL |     let y = &x as *const _;
+   |         ^
+LL |
 LL |     let _ = y.is_null();
-   |               ^^^^^^^
+   |               ------- cannot call a method on a raw pointer with an unknown pointee type
+   |
+help: consider giving `y` an explicit type, where the placeholders `_` are specified
+   |
+LL |     let y: *const _ = &x as *const _;
+   |          ++++++++++
 
 error: aborting due to 1 previous error
 
-For more information about this error, try `rustc --explain E0699`.
+For more information about this error, try `rustc --explain E0282`.
diff --git a/tests/ui/methods/call_method_unknown_pointee.rs b/tests/ui/methods/call_method_unknown_pointee.rs
index 1643b6bfa1813..a144e855ae3cb 100644
--- a/tests/ui/methods/call_method_unknown_pointee.rs
+++ b/tests/ui/methods/call_method_unknown_pointee.rs
@@ -8,10 +8,10 @@ fn main() {
     let ptr = &val as *const u32;
     unsafe {
         let _a: i32 = (ptr as *const _).read();
-        //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699]
+        //~^ ERROR type annotations needed
         let b = ptr as *const _;
+        //~^ ERROR type annotations needed
         let _b: u8 = b.read();
-        //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699]
         let _c = (ptr as *const u8).read(); // we know the type here
     }
 
@@ -19,10 +19,10 @@ fn main() {
     let ptr = &mut val as *mut u32;
     unsafe {
         let _a: i32 = (ptr as *mut _).read();
-        //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699]
+        //~^ ERROR type annotations needed
         let b = ptr as *mut _;
+        //~^ ERROR type annotations needed
         b.write(10);
-        //~^ ERROR cannot call a method on a raw pointer with an unknown pointee type [E0699]
         (ptr as *mut i32).write(1000); // we know the type here
     }
 }
diff --git a/tests/ui/methods/call_method_unknown_pointee.stderr b/tests/ui/methods/call_method_unknown_pointee.stderr
index 84ecf046e7ac2..9d0f38cf6b5c1 100644
--- a/tests/ui/methods/call_method_unknown_pointee.stderr
+++ b/tests/ui/methods/call_method_unknown_pointee.stderr
@@ -1,27 +1,49 @@
-error[E0699]: cannot call a method on a raw pointer with an unknown pointee type
+error[E0282]: type annotations needed
   --> $DIR/call_method_unknown_pointee.rs:10:41
    |
 LL |         let _a: i32 = (ptr as *const _).read();
    |                                         ^^^^
+   |                                         |
+   |                                         cannot infer type
+   |                                         cannot call a method on a raw pointer with an unknown pointee type
 
-error[E0699]: cannot call a method on a raw pointer with an unknown pointee type
-  --> $DIR/call_method_unknown_pointee.rs:13:24
+error[E0282]: type annotations needed for `*const _`
+  --> $DIR/call_method_unknown_pointee.rs:12:13
    |
+LL |         let b = ptr as *const _;
+   |             ^
+LL |
 LL |         let _b: u8 = b.read();
-   |                        ^^^^
+   |                        ---- cannot call a method on a raw pointer with an unknown pointee type
+   |
+help: consider giving `b` an explicit type, where the placeholders `_` are specified
+   |
+LL |         let b: *const _ = ptr as *const _;
+   |              ++++++++++
 
-error[E0699]: cannot call a method on a raw pointer with an unknown pointee type
+error[E0282]: type annotations needed
   --> $DIR/call_method_unknown_pointee.rs:21:39
    |
 LL |         let _a: i32 = (ptr as *mut _).read();
    |                                       ^^^^
+   |                                       |
+   |                                       cannot infer type
+   |                                       cannot call a method on a raw pointer with an unknown pointee type
 
-error[E0699]: cannot call a method on a raw pointer with an unknown pointee type
-  --> $DIR/call_method_unknown_pointee.rs:24:11
+error[E0282]: type annotations needed for `*mut _`
+  --> $DIR/call_method_unknown_pointee.rs:23:13
    |
+LL |         let b = ptr as *mut _;
+   |             ^
+LL |
 LL |         b.write(10);
-   |           ^^^^^
+   |           ----- cannot call a method on a raw pointer with an unknown pointee type
+   |
+help: consider giving `b` an explicit type, where the placeholders `_` are specified
+   |
+LL |         let b: *mut _ = ptr as *mut _;
+   |              ++++++++
 
 error: aborting due to 4 previous errors
 
-For more information about this error, try `rustc --explain E0699`.
+For more information about this error, try `rustc --explain E0282`.

From 7f9a4af0eb498bd0b1bcd7b6124ed90a1f7fac7b Mon Sep 17 00:00:00 2001
From: Oli Scherer <git-spam-no-reply9815368754983@oli-obk.de>
Date: Wed, 20 Mar 2024 11:09:17 +0000
Subject: [PATCH 2/2] Make tidy error code parsing robust against comments

---
 src/tools/tidy/src/error_codes.rs | 43 +++++++++++++++++++++----------
 1 file changed, 30 insertions(+), 13 deletions(-)

diff --git a/src/tools/tidy/src/error_codes.rs b/src/tools/tidy/src/error_codes.rs
index a03347fdc3b4e..39f7e70b69393 100644
--- a/src/tools/tidy/src/error_codes.rs
+++ b/src/tools/tidy/src/error_codes.rs
@@ -71,10 +71,12 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String
     let path = root_path.join(Path::new(ERROR_CODES_PATH));
     let file =
         fs::read_to_string(&path).unwrap_or_else(|e| panic!("failed to read `{path:?}`: {e}"));
+    let path = path.display();
 
     let mut error_codes = Vec::new();
 
-    for line in file.lines() {
+    for (line_index, line) in file.lines().enumerate() {
+        let line_index = line_index + 1;
         let line = line.trim();
 
         if line.starts_with('E') {
@@ -82,39 +84,54 @@ fn extract_error_codes(root_path: &Path, errors: &mut Vec<String>) -> Vec<String
 
             // Extract the error code from the line. Emit a fatal error if it is not in the correct
             // format.
-            let err_code = if let Some(err_code) = split_line {
-                err_code.0.to_owned()
-            } else {
+            let Some(split_line) = split_line else {
                 errors.push(format!(
-                    "Expected a line with the format `Eabcd: abcd, \
+                    "{path}:{line_index}: Expected a line with the format `Eabcd: abcd, \
                     but got \"{}\" without a `:` delimiter",
                     line,
                 ));
                 continue;
             };
 
+            let err_code = split_line.0.to_owned();
+
             // If this is a duplicate of another error code, emit a fatal error.
             if error_codes.contains(&err_code) {
-                errors.push(format!("Found duplicate error code: `{}`", err_code));
+                errors.push(format!(
+                    "{path}:{line_index}: Found duplicate error code: `{}`",
+                    err_code
+                ));
                 continue;
             }
 
             let mut chars = err_code.chars();
-            chars.next();
+            assert_eq!(chars.next(), Some('E'));
             let error_num_as_str = chars.as_str();
 
             // Ensure that the line references the correct markdown file.
-            let expected_filename = format!(" {},", error_num_as_str);
-            if expected_filename != split_line.unwrap().1 {
+            let rest = split_line.1.split_once(',');
+            let Some(rest) = rest else {
+                errors.push(format!(
+                    "{path}:{line_index}: Expected a line with the format `Eabcd: abcd, \
+                    but got \"{}\" without a `,` delimiter",
+                    line,
+                ));
+                continue;
+            };
+            if error_num_as_str != rest.0.trim() {
                 errors.push(format!(
-                    "`{}:` should be followed by `{}` but instead found `{}` in \
+                    "{path}:{line_index}: `{}:` should be followed by `{},` but instead found `{}` in \
                     `compiler/rustc_error_codes/src/lib.rs`",
                     err_code,
-                    expected_filename,
-                    split_line.unwrap().1,
+                    error_num_as_str,
+                    split_line.1,
                 ));
                 continue;
             }
+            if !rest.1.trim().is_empty() && !rest.1.trim().starts_with("//") {
+                errors.push(format!("{path}:{line_index}: should only have one error per line"));
+                continue;
+            }
 
             error_codes.push(err_code);
         }
@@ -146,7 +163,7 @@ fn check_error_codes_docs(
             return;
         }
 
-        // Make sure that the file is referenced in `error_codes.rs`
+        // Make sure that the file is referenced in `rustc_error_codes/src/lib.rs`
         let filename = path.file_name().unwrap().to_str().unwrap().split_once('.');
         let err_code = filename.unwrap().0; // `unwrap` is ok because we know the filename is in the correct format.