From 985e66362f8dc96699e2c621e4a235e8451376d6 Mon Sep 17 00:00:00 2001 From: lcnr/Bastian Kauschke Date: Tue, 19 Nov 2019 10:18:53 +0100 Subject: [PATCH 1/4] add fn any::type_name_of_val --- src/libcore/any.rs | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/src/libcore/any.rs b/src/libcore/any.rs index e2704e807d104..fc6d2c2ee2c79 100644 --- a/src/libcore/any.rs +++ b/src/libcore/any.rs @@ -446,7 +446,7 @@ impl TypeId { /// The current implementation uses the same infrastructure as compiler /// diagnostics and debuginfo, but this is not guaranteed. /// -/// # Example +/// # Examples /// /// ```rust /// assert_eq!( @@ -459,3 +459,42 @@ impl TypeId { pub const fn type_name() -> &'static str { intrinsics::type_name::() } + +/// Returns the name of the type of the pointed-to value as a string slice. +/// This is the same as `type_name::()`, but can be used where the type of a +/// variable is not easily available. +/// +/// # Note +/// +/// This is intended for diagnostic use. The exact contents and format of the +/// string are not specified, other than being a best-effort description of the +/// type. For example, `type_name_of::>(None)` could return the +/// `"Option"` or `"std::option::Option"`, but not +/// `"foobar"`. In addition, the output may change between versions of the +/// compiler. +/// +/// The type name should not be considered a unique identifier of a type; +/// multiple types may share the same type name. +/// +/// The current implementation uses the same infrastructure as compiler +/// diagnostics and debuginfo, but this is not guaranteed. +/// +/// # Examples +/// +/// Prints the default integer and float types. +/// +/// ```rust +/// #![feature(type_name_of_val)] +/// use std::any::type_name_of_val; +/// +/// let x = 1; +/// println!("{}", type_name_of_val(&x)); +/// let y = 1.0; +/// println!("{}", type_name_of_val(&y)); +/// ``` +#[unstable(feature = "type_name_of_val", issue = "66359")] +#[rustc_const_unstable(feature = "const_type_name")] +pub const fn type_name_of_val(val: &T) -> &'static str { + let _ = val; + type_name::() +} From 9b40e0bb9af6641a23586fd5999430e4c7622636 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 20 Nov 2019 16:37:17 +0100 Subject: [PATCH 2/4] made gdb pretty-printing script more robust when printing uninitialized vec. I based this solution on my reading of: https://rethinkdb.com/blog/make-debugging-easier-with-custom-pretty-printers#what-is-still-to-be-done That post claims that there is no clean way to check for garbage pointers, and so this PR adopts the same solution of tentatively attempting to convert a dererence to a string, which throws a clean exception on garbage that we can catch and recover from. I only made the change to vec and not the other pretty printers because I wanted to focus my effort on the simplest thing that would resolve issue #64343. In particular, I *considered* generalizing this fix to work on the other datatypes in the pretty-printing support library, but I don't want to invest effort in that until after we resolve our overall debugging support strategy; see also issues #60826 and #65564. --- src/etc/gdb_rust_pretty_printing.py | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/etc/gdb_rust_pretty_printing.py b/src/etc/gdb_rust_pretty_printing.py index a6b09722e1c94..5da01b96fa5e3 100755 --- a/src/etc/gdb_rust_pretty_printing.py +++ b/src/etc/gdb_rust_pretty_printing.py @@ -284,10 +284,20 @@ def to_string(self): ("(len: %i, cap: %i)" % (length, cap))) def children(self): + saw_inaccessible = False (length, data_ptr, cap) = rustpp.extract_length_ptr_and_cap_from_std_vec(self.__val) gdb_ptr = data_ptr.get_wrapped_value() for index in xrange(0, length): - yield (str(index), (gdb_ptr + index).dereference()) + if saw_inaccessible: + return + try: + # rust-lang/rust#64343: passing deref expr to `str` allows + # catching exception on garbage pointer + str((gdb_ptr + index).dereference()) + yield (str(index), (gdb_ptr + index).dereference()) + except RuntimeError: + saw_inaccessible = True + yield (str(index), "inaccessible") class RustStdVecDequePrinter(object): From 983cae77dd8681adfb021f841881185721087098 Mon Sep 17 00:00:00 2001 From: Phlosioneer Date: Wed, 20 Nov 2019 14:40:54 -0500 Subject: [PATCH 3/4] Clarify Step Documentation While the redesign is in progress (#62886), clarify the purpose of replace_zero and replace_one. --- src/libcore/iter/range.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/libcore/iter/range.rs b/src/libcore/iter/range.rs index efda3b263cc97..63036f516a0a4 100644 --- a/src/libcore/iter/range.rs +++ b/src/libcore/iter/range.rs @@ -20,10 +20,14 @@ pub trait Step: Clone + PartialOrd + Sized { /// without overflow. fn steps_between(start: &Self, end: &Self) -> Option; - /// Replaces this step with `1`, returning itself. + /// Replaces this step with `1`, returning a clone of itself. + /// + /// The output of this method should always be greater than the output of replace_zero. fn replace_one(&mut self) -> Self; - /// Replaces this step with `0`, returning itself. + /// Replaces this step with `0`, returning a clone of itself. + /// + /// The output of this method should always be less than the output of replace_one. fn replace_zero(&mut self) -> Self; /// Adds one to this step, returning the result. From df9fed17ed93018165c7e8b626a3a312438396f2 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 20 Nov 2019 14:13:24 +0100 Subject: [PATCH 4/4] Update tidy check for error codes testing --- src/tools/tidy/src/error_codes_check.rs | 68 ++++++++++++++++++------- 1 file changed, 49 insertions(+), 19 deletions(-) diff --git a/src/tools/tidy/src/error_codes_check.rs b/src/tools/tidy/src/error_codes_check.rs index bd58de81c778a..5364005840aa1 100644 --- a/src/tools/tidy/src/error_codes_check.rs +++ b/src/tools/tidy/src/error_codes_check.rs @@ -3,6 +3,8 @@ use std::collections::HashMap; use std::ffi::OsStr; +use std::fs::read_to_string; +use std::io::Read; use std::path::Path; // A few of those error codes can't be tested but all the others can and *should* be tested! @@ -50,29 +52,60 @@ const WHITELIST: &[&str] = &[ "E0729", ]; -fn extract_error_codes(f: &str, error_codes: &mut HashMap) { +fn check_error_code_explanation( + f: &str, + error_codes: &mut HashMap, + err_code: String, +) { + for line in f.lines() { + let s = line.trim(); + if s.starts_with("```") && s.contains("compile_fail") && s.contains('E') { + error_codes.insert(err_code, true); + return; + } else if s.starts_with("#### Note: this error code is no longer emitted by the compiler") { + error_codes.get_mut(&err_code).map(|x| *x = true); + return; + } + } +} + +macro_rules! some_or_continue { + ($e:expr) => ( + match $e { + Some(e) => e, + None => continue, + } + ); +} + +fn extract_error_codes(f: &str, error_codes: &mut HashMap, path: &Path) { let mut reached_no_explanation = false; - let mut last_error_code = None; for line in f.lines() { let s = line.trim(); - if s.starts_with('E') && s.ends_with(": r##\"") { + if !reached_no_explanation && s.starts_with('E') && s.contains("include_str!(\"") { if let Some(err_code) = s.splitn(2, ':').next() { let err_code = err_code.to_owned(); - last_error_code = Some(err_code.clone()); if !error_codes.contains_key(&err_code) { - error_codes.insert(err_code, false); + error_codes.insert(err_code.clone(), false); } - } - } else if s.starts_with("```") && s.contains("compile_fail") && s.contains('E') { - if let Some(err_code) = s.splitn(2, 'E').skip(1).next() { - if let Some(err_code) = err_code.splitn(2, ',').next() { - let nb = error_codes.entry(format!("E{}", err_code)).or_insert(false); - *nb = true; + // Now we extract the tests from the markdown file! + let md = some_or_continue!(s.splitn(2, "include_str!(\"").skip(1).next()); + let md_file_name = some_or_continue!(md.splitn(2, "\")").next()); + let path = some_or_continue!(path.parent()).join(md_file_name); + match read_to_string(&path) { + Ok(content) => { + check_error_code_explanation( + &content, + error_codes, + err_code, + ); + } + Err(e) => { + eprintln!("Couldn't read `{}`: {}", path.display(), e); + } } } - } else if s == ";" { - reached_no_explanation = true; } else if reached_no_explanation && s.starts_with('E') { if let Some(err_code) = s.splitn(2, ',').next() { let err_code = err_code.to_owned(); @@ -80,11 +113,8 @@ fn extract_error_codes(f: &str, error_codes: &mut HashMap) { error_codes.insert(err_code, false); } } - } else if s.starts_with("#### Note: this error code is no longer emitted by the compiler") { - if let Some(last) = last_error_code { - error_codes.get_mut(&last).map(|x| *x = true); - } - last_error_code = None; + } else if s == ";" { + reached_no_explanation = true; } } } @@ -111,7 +141,7 @@ pub fn check(path: &Path, bad: &mut bool) { &mut |entry, contents| { let file_name = entry.file_name(); if file_name == "error_codes.rs" { - extract_error_codes(contents, &mut error_codes); + extract_error_codes(contents, &mut error_codes, entry.path()); } else if entry.path().extension() == Some(OsStr::new("stderr")) { extract_error_codes_from_tests(contents, &mut error_codes); }