From 586c84a0522072b68d38d1d062b7264ab323a87e Mon Sep 17 00:00:00 2001 From: Alex Macleod Date: Sun, 21 Aug 2022 16:19:48 +0000 Subject: [PATCH 01/13] Fix rustc_parse_format precision & width spans --- compiler/rustc_builtin_macros/src/format.rs | 27 ++++--- compiler/rustc_parse_format/src/lib.rs | 81 ++++++++++----------- compiler/rustc_parse_format/src/tests.rs | 41 ++++++++--- 3 files changed, 84 insertions(+), 65 deletions(-) diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index 08026c9d35784..fe3d8e6ce98d5 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -413,7 +413,7 @@ impl<'a, 'b> Context<'a, 'b> { /// Verifies one piece of a parse string, and remembers it if valid. /// All errors are not emitted as fatal so we can continue giving errors /// about this and possibly other format strings. - fn verify_piece(&mut self, p: &parse::Piece<'_>) { + fn verify_piece(&mut self, p: &parse::Piece<'a>) { match *p { parse::String(..) => {} parse::NextArgument(ref arg) => { @@ -433,6 +433,11 @@ impl<'a, 'b> Context<'a, 'b> { let has_precision = arg.format.precision != Count::CountImplied; let has_width = arg.format.width != Count::CountImplied; + if has_precision || has_width { + // push before named params are resolved to aid diagnostics + self.arg_with_formatting.push(arg.format); + } + // argument second, if it's an implicit positional parameter // it's written second, so it should come after width/precision. let pos = match arg.position { @@ -581,7 +586,11 @@ impl<'a, 'b> Context<'a, 'b> { let mut zero_based_note = false; let count = self.pieces.len() - + self.arg_with_formatting.iter().filter(|fmt| fmt.precision_span.is_some()).count(); + + self + .arg_with_formatting + .iter() + .filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_))) + .count(); if self.names.is_empty() && !numbered_position_args && count != self.num_args() { e = self.ecx.struct_span_err( sp, @@ -647,7 +656,7 @@ impl<'a, 'b> Context<'a, 'b> { + self .arg_with_formatting .iter() - .filter(|fmt| fmt.precision_span.is_some()) + .filter(|fmt| matches!(fmt.precision, parse::CountIsParam(_))) .count(); e.span_label( span, @@ -899,26 +908,22 @@ impl<'a, 'b> Context<'a, 'b> { }, position_span: arg.position_span, format: parse::FormatSpec { - fill: arg.format.fill, + fill: None, align: parse::AlignUnknown, flags: 0, precision: parse::CountImplied, - precision_span: None, + precision_span: arg.format.precision_span, width: parse::CountImplied, - width_span: None, + width_span: arg.format.width_span, ty: arg.format.ty, ty_span: arg.format.ty_span, }, }; let fill = arg.format.fill.unwrap_or(' '); - let pos_simple = arg.position.index() == simple_arg.position.index(); - if arg.format.precision_span.is_some() || arg.format.width_span.is_some() { - self.arg_with_formatting.push(arg.format); - } - if !pos_simple || arg.format != simple_arg.format || fill != ' ' { + if !pos_simple || arg.format != simple_arg.format { self.all_pieces_simple = false; } diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index e4842d2afb705..b63a173cc29e6 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -264,9 +264,7 @@ impl<'a> Iterator for Parser<'a> { } } else { if self.is_literal { - let start = self.to_span_index(self.cur_line_start); - let end = self.to_span_index(self.input.len()); - let span = start.to(end); + let span = self.span(self.cur_line_start, self.input.len()); if self.line_spans.last() != Some(&span) { self.line_spans.push(span); } @@ -384,6 +382,12 @@ impl<'a> Parser<'a> { InnerOffset(raw + pos + 1) } + fn span(&self, start_pos: usize, end_pos: usize) -> InnerSpan { + let start = self.to_span_index(start_pos); + let end = self.to_span_index(end_pos); + start.to(end) + } + /// Forces consumption of the specified character. If the character is not /// found, an error is emitted. fn must_consume(&mut self, c: char) -> Option { @@ -472,9 +476,7 @@ impl<'a> Parser<'a> { return &self.input[start..pos]; } '\n' if self.is_literal => { - let start = self.to_span_index(self.cur_line_start); - let end = self.to_span_index(pos); - self.line_spans.push(start.to(end)); + self.line_spans.push(self.span(self.cur_line_start, pos)); self.cur_line_start = pos + 1; self.cur.next(); } @@ -537,6 +539,10 @@ impl<'a> Parser<'a> { } } + fn current_pos(&mut self) -> usize { + if let Some(&(pos, _)) = self.cur.peek() { pos } else { self.input.len() } + } + /// Parses a format specifier at the current position, returning all of the /// relevant information in the `FormatSpec` struct. fn format(&mut self) -> FormatSpec<'a> { @@ -590,39 +596,37 @@ impl<'a> Parser<'a> { // no '0' flag and '0$' as the width instead. if let Some(end) = self.consume_pos('$') { spec.width = CountIsParam(0); - - if let Some((pos, _)) = self.cur.peek().cloned() { - spec.width_span = Some(self.to_span_index(pos - 2).to(self.to_span_index(pos))); - } + spec.width_span = Some(self.span(end - 1, end + 1)); havewidth = true; - spec.width_span = Some(self.to_span_index(end - 1).to(self.to_span_index(end + 1))); } else { spec.flags |= 1 << (FlagSignAwareZeroPad as u32); } } + if !havewidth { - let width_span_start = if let Some((pos, _)) = self.cur.peek() { *pos } else { 0 }; - let (w, sp) = self.count(width_span_start); - spec.width = w; - spec.width_span = sp; + let start = self.current_pos(); + spec.width = self.count(start); + if spec.width != CountImplied { + let end = self.current_pos(); + spec.width_span = Some(self.span(start, end)); + } } if let Some(start) = self.consume_pos('.') { - if let Some(end) = self.consume_pos('*') { + if self.consume('*') { // Resolve `CountIsNextParam`. // We can do this immediately as `position` is resolved later. let i = self.curarg; self.curarg += 1; spec.precision = CountIsParam(i); - spec.precision_span = - Some(self.to_span_index(start).to(self.to_span_index(end + 1))); } else { - let (p, sp) = self.count(start); - spec.precision = p; - spec.precision_span = sp; + spec.precision = self.count(start + 1); } + let end = self.current_pos(); + spec.precision_span = Some(self.span(start, end)); } - let ty_span_start = self.cur.peek().map(|(pos, _)| *pos); + + let ty_span_start = self.current_pos(); // Optional radix followed by the actual format specifier if self.consume('x') { if self.consume('?') { @@ -642,11 +646,9 @@ impl<'a> Parser<'a> { spec.ty = "?"; } else { spec.ty = self.word(); - let ty_span_end = self.cur.peek().map(|(pos, _)| *pos); if !spec.ty.is_empty() { - spec.ty_span = ty_span_start - .and_then(|s| ty_span_end.map(|e| (s, e))) - .map(|(start, end)| self.to_span_index(start).to(self.to_span_index(end))); + let ty_span_end = self.current_pos(); + spec.ty_span = Some(self.span(ty_span_start, ty_span_end)); } } spec @@ -670,13 +672,11 @@ impl<'a> Parser<'a> { return spec; } - let ty_span_start = self.cur.peek().map(|(pos, _)| *pos); + let ty_span_start = self.current_pos(); spec.ty = self.word(); - let ty_span_end = self.cur.peek().map(|(pos, _)| *pos); if !spec.ty.is_empty() { - spec.ty_span = ty_span_start - .and_then(|s| ty_span_end.map(|e| (s, e))) - .map(|(start, end)| self.to_span_index(start).to(self.to_span_index(end))); + let ty_span_end = self.current_pos(); + spec.ty_span = Some(self.span(ty_span_start, ty_span_end)); } spec @@ -685,26 +685,21 @@ impl<'a> Parser<'a> { /// Parses a `Count` parameter at the current position. This does not check /// for 'CountIsNextParam' because that is only used in precision, not /// width. - fn count(&mut self, start: usize) -> (Count<'a>, Option) { + fn count(&mut self, start: usize) -> Count<'a> { if let Some(i) = self.integer() { - if let Some(end) = self.consume_pos('$') { - let span = self.to_span_index(start).to(self.to_span_index(end + 1)); - (CountIsParam(i), Some(span)) - } else { - (CountIs(i), None) - } + if self.consume('$') { CountIsParam(i) } else { CountIs(i) } } else { let tmp = self.cur.clone(); let word = self.word(); if word.is_empty() { self.cur = tmp; - (CountImplied, None) + CountImplied } else if let Some(end) = self.consume_pos('$') { - let span = self.to_span_index(start + 1).to(self.to_span_index(end)); - (CountIsName(word, span), None) + let name_span = self.span(start, end); + CountIsName(word, name_span) } else { self.cur = tmp; - (CountImplied, None) + CountImplied } } } @@ -737,7 +732,7 @@ impl<'a> Parser<'a> { "invalid argument name `_`", "invalid argument name", "argument name cannot be a single underscore", - self.to_span_index(start).to(self.to_span_index(end)), + self.span(start, end), ); } word diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs index 578530696105d..44ef0cd0eb5d2 100644 --- a/compiler/rustc_parse_format/src/tests.rs +++ b/compiler/rustc_parse_format/src/tests.rs @@ -1,5 +1,6 @@ use super::*; +#[track_caller] fn same(fmt: &'static str, p: &[Piece<'static>]) { let parser = Parser::new(fmt, None, None, false, ParseMode::Format); assert_eq!(parser.collect::>>(), p); @@ -190,9 +191,9 @@ fn format_counts() { align: AlignUnknown, flags: 0, precision: CountImplied, - width: CountIs(10), precision_span: None, - width_span: None, + width: CountIs(10), + width_span: Some(InnerSpan { start: 3, end: 5 }), ty: "x", ty_span: None, }, @@ -208,9 +209,9 @@ fn format_counts() { align: AlignUnknown, flags: 0, precision: CountIs(10), + precision_span: Some(InnerSpan { start: 6, end: 9 }), width: CountIsParam(10), - precision_span: None, - width_span: Some(InnerSpan::new(3, 6)), + width_span: Some(InnerSpan { start: 3, end: 6 }), ty: "x", ty_span: None, }, @@ -226,9 +227,9 @@ fn format_counts() { align: AlignUnknown, flags: 0, precision: CountIs(10), + precision_span: Some(InnerSpan { start: 6, end: 9 }), width: CountIsParam(0), - precision_span: None, - width_span: Some(InnerSpan::new(4, 6)), + width_span: Some(InnerSpan { start: 4, end: 6 }), ty: "x", ty_span: None, }, @@ -244,8 +245,8 @@ fn format_counts() { align: AlignUnknown, flags: 0, precision: CountIsParam(0), + precision_span: Some(InnerSpan { start: 3, end: 5 }), width: CountImplied, - precision_span: Some(InnerSpan::new(3, 5)), width_span: None, ty: "x", ty_span: None, @@ -279,15 +280,33 @@ fn format_counts() { fill: None, align: AlignUnknown, flags: 0, - precision: CountIsName("b", InnerSpan::new(6, 7)), - width: CountIsName("a", InnerSpan::new(4, 4)), - precision_span: None, - width_span: None, + precision: CountIsName("b", InnerSpan { start: 6, end: 7 }), + precision_span: Some(InnerSpan { start: 5, end: 8 }), + width: CountIsName("a", InnerSpan { start: 3, end: 4 }), + width_span: Some(InnerSpan { start: 3, end: 5 }), ty: "?", ty_span: None, }, })], ); + same( + "{:.4}", + &[NextArgument(Argument { + position: ArgumentImplicitlyIs(0), + position_span: InnerSpan { start: 2, end: 2 }, + format: FormatSpec { + fill: None, + align: AlignUnknown, + flags: 0, + precision: CountIs(4), + precision_span: Some(InnerSpan { start: 3, end: 5 }), + width: CountImplied, + width_span: None, + ty: "", + ty_span: None, + }, + })], + ) } #[test] fn format_flags() { From 8be37644dbc3a6dc99e6586b223bfcdcd4bb49c3 Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 10 Aug 2022 22:21:34 +0800 Subject: [PATCH 02/13] InferCtxt emit error when incorrectly tainted by errors --- compiler/rustc_infer/src/infer/at.rs | 2 +- compiler/rustc_infer/src/infer/mod.rs | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 130214a653f7c..e37c0cf0fd032 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -74,7 +74,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { evaluation_cache: self.evaluation_cache.clone(), reported_trait_errors: self.reported_trait_errors.clone(), reported_closure_mismatch: self.reported_closure_mismatch.clone(), - tainted_by_errors_flag: self.tainted_by_errors_flag.clone(), + tainted_by_errors: self.tainted_by_errors.clone(), err_count_on_creation: self.err_count_on_creation, in_snapshot: self.in_snapshot.clone(), universe: self.universe.clone(), diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 444817f396e56..c95738e0018c0 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -32,7 +32,7 @@ pub use rustc_middle::ty::IntVarValue; use rustc_middle::ty::{self, GenericParamDefKind, InferConst, Ty, TyCtxt}; use rustc_middle::ty::{ConstVid, FloatVid, IntVid, TyVid}; use rustc_span::symbol::Symbol; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use std::cell::{Cell, Ref, RefCell}; use std::fmt; @@ -316,12 +316,12 @@ pub struct InferCtxt<'a, 'tcx> { /// /// Don't read this flag directly, call `is_tainted_by_errors()` /// and `set_tainted_by_errors()`. - tainted_by_errors_flag: Cell, + tainted_by_errors: Cell>, /// Track how many errors were reported when this infcx is created. /// If the number of errors increases, that's also a sign (line /// `tainted_by_errors`) to avoid reporting certain kinds of errors. - // FIXME(matthewjasper) Merge into `tainted_by_errors_flag` + // FIXME(matthewjasper) Merge into `tainted_by_errors` err_count_on_creation: usize, /// This flag is true while there is an active snapshot. @@ -624,7 +624,7 @@ impl<'tcx> InferCtxtBuilder<'tcx> { evaluation_cache: Default::default(), reported_trait_errors: Default::default(), reported_closure_mismatch: Default::default(), - tainted_by_errors_flag: Cell::new(false), + tainted_by_errors: Cell::new(None), err_count_on_creation: tcx.sess.err_count(), in_snapshot: Cell::new(false), skip_leak_check: Cell::new(false), @@ -1227,23 +1227,25 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn is_tainted_by_errors(&self) -> bool { debug!( "is_tainted_by_errors(err_count={}, err_count_on_creation={}, \ - tainted_by_errors_flag={})", + tainted_by_errors={})", self.tcx.sess.err_count(), self.err_count_on_creation, - self.tainted_by_errors_flag.get() + self.tainted_by_errors.get().is_some() ); if self.tcx.sess.err_count() > self.err_count_on_creation { return true; // errors reported since this infcx was made } - self.tainted_by_errors_flag.get() + self.tainted_by_errors.get().is_some() } /// Set the "tainted by errors" flag to true. We call this when we /// observe an error from a prior pass. pub fn set_tainted_by_errors(&self) { debug!("set_tainted_by_errors()"); - self.tainted_by_errors_flag.set(true) + self.tainted_by_errors.set(Some( + self.tcx.sess.delay_span_bug(DUMMY_SP, "`InferCtxt` incorrectly tainted by errors"), + )); } pub fn skip_region_resolution(&self) { From f466a7563d4b0448a0b242474dd862b37e3f8d11 Mon Sep 17 00:00:00 2001 From: yukang Date: Mon, 22 Aug 2022 22:22:15 +0800 Subject: [PATCH 03/13] remove hack fix since we don't have no overflow diagnostic --- compiler/rustc_trait_selection/src/traits/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index 85ff6e23711ca..d922f893321a8 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -473,9 +473,6 @@ pub fn impossible_predicates<'tcx>( debug!("impossible_predicates(predicates={:?})", predicates); let result = tcx.infer_ctxt().enter(|infcx| { - // HACK: Set tainted by errors to gracefully exit in case of overflow. - infcx.set_tainted_by_errors(); - let param_env = ty::ParamEnv::reveal_all(); let ocx = ObligationCtxt::new(&infcx); let predicates = ocx.normalize(ObligationCause::dummy(), param_env, predicates); From 15c8e55601515583cf169e0371f62867e5719f47 Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sun, 21 Aug 2022 06:58:51 +0100 Subject: [PATCH 04/13] net listen backlog update, follow-up from #97963. FreeBSD and using system limit instead for others. --- library/std/src/os/unix/net/listener.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/library/std/src/os/unix/net/listener.rs b/library/std/src/os/unix/net/listener.rs index 3b2601e755a97..02090afc82f7e 100644 --- a/library/std/src/os/unix/net/listener.rs +++ b/library/std/src/os/unix/net/listener.rs @@ -73,10 +73,8 @@ impl UnixListener { unsafe { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path.as_ref())?; - #[cfg(target_os = "linux")] - const backlog: libc::c_int = -1; - #[cfg(not(target_os = "linux"))] - const backlog: libc::c_int = 128; + const backlog: libc::c_int = + if cfg!(any(target_os = "linux", target_os = "freebsd")) { -1 } else { 128 }; cvt(libc::bind(inner.as_inner().as_raw_fd(), &addr as *const _ as *const _, len as _))?; cvt(libc::listen(inner.as_inner().as_raw_fd(), backlog))?; From 8c2413c4c609127db344044d6740c9de03aa7ce2 Mon Sep 17 00:00:00 2001 From: Peter Medus <16763503+Facel3ss1@users.noreply.github.com> Date: Fri, 19 Aug 2022 18:29:33 +0100 Subject: [PATCH 05/13] Migrate rustc_plugin_impl to SessionDiagnostic --- Cargo.lock | 1 + .../locales/en-US/plugin_impl.ftl | 4 ++++ compiler/rustc_error_messages/src/lib.rs | 1 + compiler/rustc_plugin_impl/Cargo.toml | 1 + compiler/rustc_plugin_impl/src/errors.rs | 20 +++++++++++++++++++ compiler/rustc_plugin_impl/src/lib.rs | 3 +++ compiler/rustc_plugin_impl/src/load.rs | 16 +++++---------- 7 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 compiler/rustc_error_messages/locales/en-US/plugin_impl.ftl create mode 100644 compiler/rustc_plugin_impl/src/errors.rs diff --git a/Cargo.lock b/Cargo.lock index cb245ce0ff828..a2037bb799a4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4321,6 +4321,7 @@ dependencies = [ "rustc_ast", "rustc_errors", "rustc_lint", + "rustc_macros", "rustc_metadata", "rustc_session", "rustc_span", diff --git a/compiler/rustc_error_messages/locales/en-US/plugin_impl.ftl b/compiler/rustc_error_messages/locales/en-US/plugin_impl.ftl new file mode 100644 index 0000000000000..8db32a42c1dea --- /dev/null +++ b/compiler/rustc_error_messages/locales/en-US/plugin_impl.ftl @@ -0,0 +1,4 @@ +plugin_impl_load_plugin_error = {$msg} + +plugin_impl_malformed_plugin_attribute = malformed `plugin` attribute + .label = malformed attribute diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 3569c7f063064..3e66d12bb37ec 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -41,6 +41,7 @@ fluent_messages! { lint => "../locales/en-US/lint.ftl", parser => "../locales/en-US/parser.ftl", passes => "../locales/en-US/passes.ftl", + plugin_impl => "../locales/en-US/plugin_impl.ftl", privacy => "../locales/en-US/privacy.ftl", typeck => "../locales/en-US/typeck.ftl", } diff --git a/compiler/rustc_plugin_impl/Cargo.toml b/compiler/rustc_plugin_impl/Cargo.toml index b6ea533c80bdd..c409b6c3e5440 100644 --- a/compiler/rustc_plugin_impl/Cargo.toml +++ b/compiler/rustc_plugin_impl/Cargo.toml @@ -11,6 +11,7 @@ doctest = false libloading = "0.7.1" rustc_errors = { path = "../rustc_errors" } rustc_lint = { path = "../rustc_lint" } +rustc_macros = { path = "../rustc_macros" } rustc_metadata = { path = "../rustc_metadata" } rustc_ast = { path = "../rustc_ast" } rustc_session = { path = "../rustc_session" } diff --git a/compiler/rustc_plugin_impl/src/errors.rs b/compiler/rustc_plugin_impl/src/errors.rs new file mode 100644 index 0000000000000..2bdb6e4feca9d --- /dev/null +++ b/compiler/rustc_plugin_impl/src/errors.rs @@ -0,0 +1,20 @@ +//! Errors emitted by plugin_impl + +use rustc_macros::SessionDiagnostic; +use rustc_span::Span; + +#[derive(SessionDiagnostic)] +#[diag(plugin_impl::load_plugin_error)] +pub struct LoadPluginError { + #[primary_span] + pub span: Span, + pub msg: String, +} + +#[derive(SessionDiagnostic)] +#[diag(plugin_impl::malformed_plugin_attribute, code = "E0498")] +pub struct MalformedPluginAttribute { + #[primary_span] + #[label] + pub span: Span, +} diff --git a/compiler/rustc_plugin_impl/src/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs index 1195045bdea4a..9ac27c65da82e 100644 --- a/compiler/rustc_plugin_impl/src/lib.rs +++ b/compiler/rustc_plugin_impl/src/lib.rs @@ -8,9 +8,12 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![recursion_limit = "256"] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] use rustc_lint::LintStore; +mod errors; pub mod load; /// Structure used to register plugins. diff --git a/compiler/rustc_plugin_impl/src/load.rs b/compiler/rustc_plugin_impl/src/load.rs index 618682da4e597..8e75e969ae032 100644 --- a/compiler/rustc_plugin_impl/src/load.rs +++ b/compiler/rustc_plugin_impl/src/load.rs @@ -1,16 +1,14 @@ //! Used by `rustc` when loading a plugin. +use crate::errors::{LoadPluginError, MalformedPluginAttribute}; use crate::Registry; use libloading::Library; use rustc_ast::Crate; -use rustc_errors::struct_span_err; use rustc_metadata::locator; use rustc_session::cstore::MetadataLoader; use rustc_session::Session; use rustc_span::symbol::{sym, Ident}; -use rustc_span::Span; -use std::borrow::ToOwned; use std::env; use std::mem; use std::path::PathBuf; @@ -18,12 +16,6 @@ use std::path::PathBuf; /// Pointer to a registrar function. type PluginRegistrarFn = fn(&mut Registry<'_>); -fn call_malformed_plugin_attribute(sess: &Session, span: Span) { - struct_span_err!(sess, span, E0498, "malformed `plugin` attribute") - .span_label(span, "malformed attribute") - .emit(); -} - /// Read plugin metadata and dynamically load registrar functions. pub fn load_plugins( sess: &Session, @@ -42,7 +34,9 @@ pub fn load_plugins( Some(ident) if plugin.is_word() => { load_plugin(&mut plugins, sess, metadata_loader, ident) } - _ => call_malformed_plugin_attribute(sess, plugin.span()), + _ => { + sess.emit_err(MalformedPluginAttribute { span: plugin.span() }); + } } } } @@ -60,7 +54,7 @@ fn load_plugin( let fun = dylink_registrar(lib).unwrap_or_else(|err| { // This is fatal: there are almost certainly macros we need inside this crate, so // continuing would spew "macro undefined" errors. - sess.span_fatal(ident.span, &err.to_string()); + sess.emit_fatal(LoadPluginError { span: ident.span, msg: err.to_string() }); }); plugins.push(fun); } From bf7611d55ee6e24647aefc4d1c82b1dba0164536 Mon Sep 17 00:00:00 2001 From: Jane Losare-Lusby Date: Fri, 29 Jul 2022 18:54:47 +0000 Subject: [PATCH 06/13] Move error trait into core --- library/alloc/src/boxed.rs | 306 +++++++++++ library/alloc/src/boxed/thin.rs | 10 + .../alloc/src/collections/btree/map/entry.rs | 11 + library/alloc/src/collections/mod.rs | 4 + library/alloc/src/ffi/c_str.rs | 26 + library/alloc/src/lib.rs | 4 + library/alloc/src/string.rs | 20 + library/alloc/src/sync.rs | 22 + library/core/src/alloc/layout.rs | 6 + library/core/src/alloc/mod.rs | 10 + library/core/src/array/mod.rs | 11 + library/core/src/char/decode.rs | 11 + library/core/src/char/mod.rs | 6 + library/core/src/convert/mod.rs | 10 + library/core/src/error.md | 137 +++++ library/core/src/error.rs | 508 ++++++++++++++++++ library/core/src/lib.rs | 2 + library/core/src/num/error.rs | 20 + library/core/src/num/mod.rs | 12 + library/core/src/str/error.rs | 20 + library/core/src/str/mod.rs | 4 + library/std/src/collections/hash/map.rs | 11 + library/std/src/error.rs | 307 +++-------- library/std/src/io/error.rs | 9 + library/std/src/lib.rs | 3 + 25 files changed, 1264 insertions(+), 226 deletions(-) create mode 100644 library/core/src/error.md create mode 100644 library/core/src/error.rs diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 6955d863c99e7..67925941c92c6 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -151,6 +151,8 @@ use core::async_iter::AsyncIterator; use core::borrow; use core::cmp::Ordering; use core::convert::{From, TryFrom}; +#[cfg(not(bootstrap))] +use core::error::Error; use core::fmt; use core::future::Future; use core::hash::{Hash, Hasher}; @@ -174,6 +176,9 @@ use crate::borrow::Cow; use crate::raw_vec::RawVec; #[cfg(not(no_global_oom_handling))] use crate::str::from_boxed_utf8_unchecked; +#[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] +use crate::string::String; #[cfg(not(no_global_oom_handling))] use crate::vec::Vec; @@ -2085,3 +2090,304 @@ impl AsyncIterator for Box { (**self).size_hint() } } + +#[cfg(not(bootstrap))] +impl dyn Error { + #[inline] + #[stable(feature = "error_downcast", since = "1.3.0")] + #[rustc_allow_incoherent_impl] + /// Attempts to downcast the box to a concrete type. + pub fn downcast(self: Box) -> Result, Box> { + if self.is::() { + unsafe { + let raw: *mut dyn Error = Box::into_raw(self); + Ok(Box::from_raw(raw as *mut T)) + } + } else { + Err(self) + } + } +} + +#[cfg(not(bootstrap))] +impl dyn Error + Send { + #[inline] + #[stable(feature = "error_downcast", since = "1.3.0")] + #[rustc_allow_incoherent_impl] + /// Attempts to downcast the box to a concrete type. + pub fn downcast(self: Box) -> Result, Box> { + let err: Box = self; + ::downcast(err).map_err(|s| unsafe { + // Reapply the `Send` marker. + mem::transmute::, Box>(s) + }) + } +} + +#[cfg(not(bootstrap))] +impl dyn Error + Send + Sync { + #[inline] + #[stable(feature = "error_downcast", since = "1.3.0")] + #[rustc_allow_incoherent_impl] + /// Attempts to downcast the box to a concrete type. + pub fn downcast(self: Box) -> Result, Box> { + let err: Box = self; + ::downcast(err).map_err(|s| unsafe { + // Reapply the `Send + Sync` marker. + mem::transmute::, Box>(s) + }) + } +} + +#[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, E: Error + 'a> From for Box { + /// Converts a type of [`Error`] into a box of dyn [`Error`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::fmt; + /// use std::mem; + /// + /// #[derive(Debug)] + /// struct AnError; + /// + /// impl fmt::Display for AnError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "An error") + /// } + /// } + /// + /// impl Error for AnError {} + /// + /// let an_error = AnError; + /// assert!(0 == mem::size_of_val(&an_error)); + /// let a_boxed_error = Box::::from(an_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: E) -> Box { + Box::new(err) + } +} + +#[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, E: Error + Send + Sync + 'a> From for Box { + /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of + /// dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::fmt; + /// use std::mem; + /// + /// #[derive(Debug)] + /// struct AnError; + /// + /// impl fmt::Display for AnError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "An error") + /// } + /// } + /// + /// impl Error for AnError {} + /// + /// unsafe impl Send for AnError {} + /// + /// unsafe impl Sync for AnError {} + /// + /// let an_error = AnError; + /// assert!(0 == mem::size_of_val(&an_error)); + /// let a_boxed_error = Box::::from(an_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: E) -> Box { + Box::new(err) + } +} + +#[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "rust1", since = "1.0.0")] +impl From for Box { + /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// let a_string_error = "a string error".to_string(); + /// let a_boxed_error = Box::::from(a_string_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + #[inline] + fn from(err: String) -> Box { + struct StringError(String); + + impl Error for StringError { + #[allow(deprecated)] + fn description(&self) -> &str { + &self.0 + } + } + + impl fmt::Display for StringError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } + } + + // Purposefully skip printing "StringError(..)" + impl fmt::Debug for StringError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } + } + + Box::new(StringError(err)) + } +} + +#[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "string_box_error", since = "1.6.0")] +impl From for Box { + /// Converts a [`String`] into a box of dyn [`Error`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// let a_string_error = "a string error".to_string(); + /// let a_boxed_error = Box::::from(a_string_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(str_err: String) -> Box { + let err1: Box = From::from(str_err); + let err2: Box = err1; + err2 + } +} + +#[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> From<&str> for Box { + /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// [`str`]: prim@str + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// let a_str_error = "a str error"; + /// let a_boxed_error = Box::::from(a_str_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + #[inline] + fn from(err: &str) -> Box { + From::from(String::from(err)) + } +} + +#[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "string_box_error", since = "1.6.0")] +impl From<&str> for Box { + /// Converts a [`str`] into a box of dyn [`Error`]. + /// + /// [`str`]: prim@str + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// + /// let a_str_error = "a str error"; + /// let a_boxed_error = Box::::from(a_str_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: &str) -> Box { + From::from(String::from(err)) + } +} + +#[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "cow_box_error", since = "1.22.0")] +impl<'a, 'b> From> for Box { + /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// use std::borrow::Cow; + /// + /// let a_cow_str_error = Cow::from("a str error"); + /// let a_boxed_error = Box::::from(a_cow_str_error); + /// assert!( + /// mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: Cow<'b, str>) -> Box { + From::from(String::from(err)) + } +} + +#[cfg(not(bootstrap))] +#[cfg(not(no_global_oom_handling))] +#[stable(feature = "cow_box_error", since = "1.22.0")] +impl<'a> From> for Box { + /// Converts a [`Cow`] into a box of dyn [`Error`]. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::mem; + /// use std::borrow::Cow; + /// + /// let a_cow_str_error = Cow::from("a str error"); + /// let a_boxed_error = Box::::from(a_cow_str_error); + /// assert!(mem::size_of::>() == mem::size_of_val(&a_boxed_error)) + /// ``` + fn from(err: Cow<'a, str>) -> Box { + From::from(String::from(err)) + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "box_error", since = "1.8.0")] +impl core::error::Error for Box { + #[allow(deprecated, deprecated_in_future)] + fn description(&self) -> &str { + core::error::Error::description(&**self) + } + + #[allow(deprecated)] + fn cause(&self) -> Option<&dyn core::error::Error> { + core::error::Error::cause(&**self) + } + + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { + core::error::Error::source(&**self) + } +} diff --git a/library/alloc/src/boxed/thin.rs b/library/alloc/src/boxed/thin.rs index 649ccfcaa9ed8..0a20c74b00fdc 100644 --- a/library/alloc/src/boxed/thin.rs +++ b/library/alloc/src/boxed/thin.rs @@ -2,6 +2,8 @@ // https://github.com/matthieu-m/rfc2580/blob/b58d1d3cba0d4b5e859d3617ea2d0943aaa31329/examples/thin.rs // by matthieu-m use crate::alloc::{self, Layout, LayoutError}; +#[cfg(not(bootstrap))] +use core::error::Error; use core::fmt::{self, Debug, Display, Formatter}; use core::marker::PhantomData; #[cfg(not(no_global_oom_handling))] @@ -271,3 +273,11 @@ impl WithHeader { Layout::new::().extend(value_layout) } } + +#[cfg(not(bootstrap))] +#[unstable(feature = "thin_box", issue = "92791")] +impl Error for ThinBox { + fn source(&self) -> Option<&(dyn Error + 'static)> { + self.deref().source() + } +} diff --git a/library/alloc/src/collections/btree/map/entry.rs b/library/alloc/src/collections/btree/map/entry.rs index b6eecf9b0e952..cd7cdc1920719 100644 --- a/library/alloc/src/collections/btree/map/entry.rs +++ b/library/alloc/src/collections/btree/map/entry.rs @@ -133,6 +133,17 @@ impl<'a, K: Debug + Ord, V: Debug, A: Allocator + Clone> fmt::Display } } +#[cfg(not(bootstrap))] +#[unstable(feature = "map_try_insert", issue = "82766")] +impl<'a, K: core::fmt::Debug + Ord, V: core::fmt::Debug> core::error::Error + for crate::collections::btree_map::OccupiedError<'a, K, V> +{ + #[allow(deprecated)] + fn description(&self) -> &str { + "key already exists" + } +} + impl<'a, K: Ord, V, A: Allocator + Clone> Entry<'a, K, V, A> { /// Ensures a value is in the entry by inserting the default if empty, and returns /// a mutable reference to the value in the entry. diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 628a5b155673c..21d0def0866ed 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -152,3 +152,7 @@ trait SpecExtend { /// Extends `self` with the contents of the given iterator. fn spec_extend(&mut self, iter: I); } + +#[cfg(not(bootstrap))] +#[stable(feature = "try_reserve", since = "1.57.0")] +impl core::error::Error for TryReserveError {} diff --git a/library/alloc/src/ffi/c_str.rs b/library/alloc/src/ffi/c_str.rs index be21d8c722d78..aede6d54c6c17 100644 --- a/library/alloc/src/ffi/c_str.rs +++ b/library/alloc/src/ffi/c_str.rs @@ -1121,3 +1121,29 @@ impl CStr { CString::from(self) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl core::error::Error for NulError { + #[allow(deprecated)] + fn description(&self) -> &str { + "nul byte found in data" + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] +impl core::error::Error for FromVecWithNulError {} + +#[cfg(not(bootstrap))] +#[stable(feature = "cstring_into", since = "1.7.0")] +impl core::error::Error for IntoStringError { + #[allow(deprecated)] + fn description(&self) -> &str { + "C string contained non-utf8 bytes" + } + + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { + Some(self.__source()) + } +} diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 62fd595572613..ad6d19bbc6875 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -111,6 +111,8 @@ #![feature(const_pin)] #![feature(cstr_from_bytes_until_nul)] #![feature(dispatch_from_dyn)] +#![cfg_attr(not(bootstrap), feature(error_generic_member_access))] +#![cfg_attr(not(bootstrap), feature(error_in_core))] #![feature(exact_size_is_empty)] #![feature(extend_one)] #![feature(fmt_internals)] @@ -127,6 +129,7 @@ #![feature(nonnull_slice_from_raw_parts)] #![feature(pattern)] #![feature(pointer_byte_offsets)] +#![cfg_attr(not(bootstrap), feature(provide_any))] #![feature(ptr_internals)] #![feature(ptr_metadata)] #![feature(ptr_sub_ptr)] @@ -179,6 +182,7 @@ #![feature(unboxed_closures)] #![feature(unsized_fn_params)] #![feature(c_unwind)] +#![feature(with_negative_coherence)] // // Rustdoc features: #![feature(doc_cfg)] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 7bee894d3e404..81922b5388691 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -44,6 +44,8 @@ #[cfg(not(no_global_oom_handling))] use core::char::{decode_utf16, REPLACEMENT_CHARACTER}; +#[cfg(not(bootstrap))] +use core::error::Error; use core::fmt; use core::hash; use core::iter::FusedIterator; @@ -1938,6 +1940,24 @@ impl fmt::Display for FromUtf16Error { } } +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for FromUtf8Error { + #[allow(deprecated)] + fn description(&self) -> &str { + "invalid utf-8" + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for FromUtf16Error { + #[allow(deprecated)] + fn description(&self) -> &str { + "invalid utf-16" + } +} + #[cfg(not(no_global_oom_handling))] #[stable(feature = "rust1", since = "1.0.0")] impl Clone for String { diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 4c03cc3ed158a..4377edeee8710 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -2763,3 +2763,25 @@ fn data_offset_align(align: usize) -> usize { let layout = Layout::new::>(); layout.size() + layout.padding_needed_for(align) } + +#[cfg(not(bootstrap))] +#[stable(feature = "arc_error", since = "1.52.0")] +impl core::error::Error for Arc { + #[allow(deprecated, deprecated_in_future)] + fn description(&self) -> &str { + core::error::Error::description(&**self) + } + + #[allow(deprecated)] + fn cause(&self) -> Option<&dyn core::error::Error> { + core::error::Error::cause(&**self) + } + + fn source(&self) -> Option<&(dyn core::error::Error + 'static)> { + core::error::Error::source(&**self) + } + + fn provide<'a>(&'a self, req: &mut core::any::Demand<'a>) { + core::error::Error::provide(&**self, req); + } +} diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index 3473ac09e956f..f03502429ab21 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -5,6 +5,8 @@ // Your performance intuition is useless. Run perf. use crate::cmp; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use crate::mem::{self, ValidAlign}; use crate::ptr::NonNull; @@ -461,6 +463,10 @@ pub type LayoutErr = LayoutError; #[derive(Clone, PartialEq, Eq, Debug)] pub struct LayoutError; +#[cfg(not(bootstrap))] +#[stable(feature = "alloc_layout", since = "1.28.0")] +impl Error for LayoutError {} + // (we need this for downstream impl of trait Error) #[stable(feature = "alloc_layout", since = "1.28.0")] impl fmt::Display for LayoutError { diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index 6cc6e359e65b6..94efa76664f6a 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -21,6 +21,8 @@ pub use self::layout::LayoutErr; #[stable(feature = "alloc_layout_error", since = "1.50.0")] pub use self::layout::LayoutError; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use crate::ptr::{self, NonNull}; @@ -32,6 +34,14 @@ use crate::ptr::{self, NonNull}; #[derive(Copy, Clone, PartialEq, Eq, Debug)] pub struct AllocError; +#[cfg(not(bootstrap))] +#[unstable( + feature = "allocator_api", + reason = "the precise API and guarantees it provides may be tweaked.", + issue = "32838" +)] +impl Error for AllocError {} + // (we need this for downstream impl of trait Error) #[unstable(feature = "allocator_api", issue = "32838")] impl fmt::Display for AllocError { diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index db5bfcab9d2b1..9effb37901609 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -7,6 +7,8 @@ use crate::borrow::{Borrow, BorrowMut}; use crate::cmp::Ordering; use crate::convert::{Infallible, TryFrom}; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use crate::hash::{self, Hash}; use crate::iter::TrustedLen; @@ -119,6 +121,15 @@ impl fmt::Display for TryFromSliceError { } } +#[cfg(not(bootstrap))] +#[stable(feature = "try_from", since = "1.34.0")] +impl Error for TryFromSliceError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + impl TryFromSliceError { #[unstable( feature = "array_error_internals", diff --git a/library/core/src/char/decode.rs b/library/core/src/char/decode.rs index 71297acd17145..dc8ea66cc6d0e 100644 --- a/library/core/src/char/decode.rs +++ b/library/core/src/char/decode.rs @@ -1,5 +1,7 @@ //! UTF-8 and UTF-16 decoding iterators +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use super::from_u32_unchecked; @@ -121,3 +123,12 @@ impl fmt::Display for DecodeUtf16Error { write!(f, "unpaired surrogate found: {:x}", self.code) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "decode_utf16", since = "1.9.0")] +impl Error for DecodeUtf16Error { + #[allow(deprecated)] + fn description(&self) -> &str { + "unpaired surrogate found" + } +} diff --git a/library/core/src/char/mod.rs b/library/core/src/char/mod.rs index a4bdd38f65530..72d63ac4b4b41 100644 --- a/library/core/src/char/mod.rs +++ b/library/core/src/char/mod.rs @@ -38,6 +38,8 @@ pub use self::methods::encode_utf16_raw; #[unstable(feature = "char_internals", reason = "exposed only for libstd", issue = "none")] pub use self::methods::encode_utf8_raw; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt::{self, Write}; use crate::iter::FusedIterator; @@ -584,3 +586,7 @@ impl fmt::Display for TryFromCharError { "unicode code point out of range".fmt(fmt) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "u8_from_char", since = "1.59.0")] +impl Error for TryFromCharError {} diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index b30c8a4aeabdd..5bddfd1a413e7 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -34,6 +34,8 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; use crate::hash::{Hash, Hasher}; @@ -715,6 +717,14 @@ impl fmt::Display for Infallible { } } +#[cfg(not(bootstrap))] +#[stable(feature = "str_parse_error2", since = "1.8.0")] +impl Error for Infallible { + fn description(&self) -> &str { + match *self {} + } +} + #[stable(feature = "convert_infallible", since = "1.34.0")] impl PartialEq for Infallible { fn eq(&self, _: &Infallible) -> bool { diff --git a/library/core/src/error.md b/library/core/src/error.md new file mode 100644 index 0000000000000..891abebbfd39b --- /dev/null +++ b/library/core/src/error.md @@ -0,0 +1,137 @@ +Interfaces for working with Errors. + +# Error Handling In Rust + +The Rust language provides two complementary systems for constructing / +representing, reporting, propagating, reacting to, and discarding errors. +These responsibilities are collectively known as "error handling." The +components of the first system, the panic runtime and interfaces, are most +commonly used to represent bugs that have been detected in your program. The +components of the second system, `Result`, the error traits, and user +defined types, are used to represent anticipated runtime failure modes of +your program. + +## The Panic Interfaces + +The following are the primary interfaces of the panic system and the +responsibilities they cover: + +* [`panic!`] and [`panic_any`] (Constructing, Propagated automatically) +* [`PanicInfo`] (Reporting) +* [`set_hook`], [`take_hook`], and [`#[panic_handler]`][panic-handler] (Reporting) +* [`catch_unwind`] and [`resume_unwind`] (Discarding, Propagating) + +The following are the primary interfaces of the error system and the +responsibilities they cover: + +* [`Result`] (Propagating, Reacting) +* The [`Error`] trait (Reporting) +* User defined types (Constructing / Representing) +* [`match`] and [`downcast`] (Reacting) +* The question mark operator ([`?`]) (Propagating) +* The partially stable [`Try`] traits (Propagating, Constructing) +* [`Termination`] (Reporting) + +## Converting Errors into Panics + +The panic and error systems are not entirely distinct. Often times errors +that are anticipated runtime failures in an API might instead represent bugs +to a caller. For these situations the standard library provides APIs for +constructing panics with an `Error` as it's source. + +* [`Result::unwrap`] +* [`Result::expect`] + +These functions are equivalent, they either return the inner value if the +`Result` is `Ok` or panic if the `Result` is `Err` printing the inner error +as the source. The only difference between them is that with `expect` you +provide a panic error message to be printed alongside the source, whereas +`unwrap` has a default message indicating only that you unwraped an `Err`. + +Of the two, `expect` is generally preferred since its `msg` field allows you +to convey your intent and assumptions which makes tracking down the source +of a panic easier. `unwrap` on the other hand can still be a good fit in +situations where you can trivially show that a piece of code will never +panic, such as `"127.0.0.1".parse::().unwrap()` or early +prototyping. + +# Common Message Styles + +There are two common styles for how people word `expect` messages. Using +the message to present information to users encountering a panic +("expect as error message") or using the message to present information +to developers debugging the panic ("expect as precondition"). + +In the former case the expect message is used to describe the error that +has occurred which is considered a bug. Consider the following example: + +```should_panic +// Read environment variable, panic if it is not present +let path = std::env::var("IMPORTANT_PATH").unwrap(); +``` + +In the "expect as error message" style we would use expect to describe +that the environment variable was not set when it should have been: + +```should_panic +let path = std::env::var("IMPORTANT_PATH") + .expect("env variable `IMPORTANT_PATH` is not set"); +``` + +In the "expect as precondition" style, we would instead describe the +reason we _expect_ the `Result` should be `Ok`. With this style we would +prefer to write: + +```should_panic +let path = std::env::var("IMPORTANT_PATH") + .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`"); +``` + +The "expect as error message" style does not work as well with the +default output of the std panic hooks, and often ends up repeating +information that is already communicated by the source error being +unwrapped: + +```text +thread 'main' panicked at 'env variable `IMPORTANT_PATH` is not set: NotPresent', src/main.rs:4:6 +``` + +In this example we end up mentioning that an env variable is not set, +followed by our source message that says the env is not present, the +only additional information we're communicating is the name of the +environment variable being checked. + +The "expect as precondition" style instead focuses on source code +readability, making it easier to understand what must have gone wrong in +situations where panics are being used to represent bugs exclusively. +Also, by framing our expect in terms of what "SHOULD" have happened to +prevent the source error, we end up introducing new information that is +independent from our source error. + +```text +thread 'main' panicked at 'env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent', src/main.rs:4:6 +``` + +In this example we are communicating not only the name of the +environment variable that should have been set, but also an explanation +for why it should have been set, and we let the source error display as +a clear contradiction to our expectation. + +**Hint**: If you're having trouble remembering how to phrase +expect-as-precondition style error messages remember to focus on the word +"should" as in "env variable should be set by blah" or "the given binary +should be available and executable by the current user". + +[`panic_any`]: ../../std/panic/fn.panic_any.html +[`PanicInfo`]: crate::panic::PanicInfo +[`catch_unwind`]: ../../std/panic/fn.catch_unwind.html +[`resume_unwind`]: ../../std/panic/fn.resume_unwind.html +[`downcast`]: crate::error::Error +[`Termination`]: ../../std/process/trait.Termination.html +[`Try`]: crate::ops::Try +[panic hook]: ../../std/panic/fn.set_hook.html +[`set_hook`]: ../../std/panic/fn.set_hook.html +[`take_hook`]: ../../std/panic/fn.take_hook.html +[panic-handler]: +[`match`]: ../../std/keyword.match.html +[`?`]: ../../std/result/index.html#the-question-mark-operator- diff --git a/library/core/src/error.rs b/library/core/src/error.rs new file mode 100644 index 0000000000000..d11debb34adca --- /dev/null +++ b/library/core/src/error.rs @@ -0,0 +1,508 @@ +#![doc = include_str!("error.md")] +#![unstable(feature = "error_in_core", issue = "none")] + +// A note about crates and the facade: +// +// Originally, the `Error` trait was defined in libcore, and the impls +// were scattered about. However, coherence objected to this +// arrangement, because to create the blanket impls for `Box` required +// knowing that `&str: !Error`, and we have no means to deal with that +// sort of conflict just now. Therefore, for the time being, we have +// moved the `Error` trait into libstd. As we evolve a sol'n to the +// coherence challenge (e.g., specialization, neg impls, etc) we can +// reconsider what crate these items belong in. + +#[cfg(test)] +mod tests; + +use crate::any::{Demand, Provider, TypeId}; +use crate::fmt::{Debug, Display}; + +/// `Error` is a trait representing the basic expectations for error values, +/// i.e., values of type `E` in [`Result`]. +/// +/// Errors must describe themselves through the [`Display`] and [`Debug`] +/// traits. Error messages are typically concise lowercase sentences without +/// trailing punctuation: +/// +/// ``` +/// let err = "NaN".parse::().unwrap_err(); +/// assert_eq!(err.to_string(), "invalid digit found in string"); +/// ``` +/// +/// Errors may provide cause chain information. [`Error::source()`] is generally +/// used when errors cross "abstraction boundaries". If one module must report +/// an error that is caused by an error from a lower-level module, it can allow +/// accessing that error via [`Error::source()`]. This makes it possible for the +/// high-level module to provide its own errors while also revealing some of the +/// implementation for debugging via `source` chains. +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg_attr(not(test), rustc_diagnostic_item = "Error")] +#[rustc_has_incoherent_inherent_impls] +pub trait Error: Debug + Display { + /// The lower-level source of this error, if any. + /// + /// # Examples + /// + /// ``` + /// use std::error::Error; + /// use std::fmt; + /// + /// #[derive(Debug)] + /// struct SuperError { + /// source: SuperErrorSideKick, + /// } + /// + /// impl fmt::Display for SuperError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "SuperError is here!") + /// } + /// } + /// + /// impl Error for SuperError { + /// fn source(&self) -> Option<&(dyn Error + 'static)> { + /// Some(&self.source) + /// } + /// } + /// + /// #[derive(Debug)] + /// struct SuperErrorSideKick; + /// + /// impl fmt::Display for SuperErrorSideKick { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "SuperErrorSideKick is here!") + /// } + /// } + /// + /// impl Error for SuperErrorSideKick {} + /// + /// fn get_super_error() -> Result<(), SuperError> { + /// Err(SuperError { source: SuperErrorSideKick }) + /// } + /// + /// fn main() { + /// match get_super_error() { + /// Err(e) => { + /// println!("Error: {e}"); + /// println!("Caused by: {}", e.source().unwrap()); + /// } + /// _ => println!("No error"), + /// } + /// } + /// ``` + #[stable(feature = "error_source", since = "1.30.0")] + fn source(&self) -> Option<&(dyn Error + 'static)> { + None + } + + /// Gets the `TypeId` of `self`. + #[doc(hidden)] + #[unstable( + feature = "error_type_id", + reason = "this is memory-unsafe to override in user code", + issue = "60784" + )] + fn type_id(&self, _: private::Internal) -> TypeId + where + Self: 'static, + { + TypeId::of::() + } + + /// ``` + /// if let Err(e) = "xc".parse::() { + /// // Print `e` itself, no need for description(). + /// eprintln!("Error: {e}"); + /// } + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + #[deprecated(since = "1.42.0", note = "use the Display impl or to_string()")] + fn description(&self) -> &str { + "description() is deprecated; use Display" + } + + #[stable(feature = "rust1", since = "1.0.0")] + #[deprecated( + since = "1.33.0", + note = "replaced by Error::source, which can support downcasting" + )] + #[allow(missing_docs)] + fn cause(&self) -> Option<&dyn Error> { + self.source() + } + + /// Provides type based access to context intended for error reports. + /// + /// Used in conjunction with [`Demand::provide_value`] and [`Demand::provide_ref`] to extract + /// references to member variables from `dyn Error` trait objects. + /// + /// # Example + /// + /// ```rust + /// #![feature(provide_any)] + /// #![feature(error_generic_member_access)] + /// use core::fmt; + /// use core::any::Demand; + /// + /// #[derive(Debug)] + /// struct MyBacktrace { + /// // ... + /// } + /// + /// impl MyBacktrace { + /// fn new() -> MyBacktrace { + /// // ... + /// # MyBacktrace {} + /// } + /// } + /// + /// #[derive(Debug)] + /// struct SourceError { + /// // ... + /// } + /// + /// impl fmt::Display for SourceError { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "Example Source Error") + /// } + /// } + /// + /// impl std::error::Error for SourceError {} + /// + /// #[derive(Debug)] + /// struct Error { + /// source: SourceError, + /// backtrace: MyBacktrace, + /// } + /// + /// impl fmt::Display for Error { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "Example Error") + /// } + /// } + /// + /// impl std::error::Error for Error { + /// fn provide<'a>(&'a self, req: &mut Demand<'a>) { + /// req + /// .provide_ref::(&self.backtrace) + /// .provide_ref::(&self.source); + /// } + /// } + /// + /// fn main() { + /// let backtrace = MyBacktrace::new(); + /// let source = SourceError {}; + /// let error = Error { source, backtrace }; + /// let dyn_error = &error as &dyn std::error::Error; + /// let backtrace_ref = dyn_error.request_ref::().unwrap(); + /// + /// assert!(core::ptr::eq(&error.backtrace, backtrace_ref)); + /// } + /// ``` + #[unstable(feature = "error_generic_member_access", issue = "99301")] + #[allow(unused_variables)] + fn provide<'a>(&'a self, req: &mut Demand<'a>) {} +} + +#[unstable(feature = "error_generic_member_access", issue = "99301")] +impl Provider for E +where + E: Error + ?Sized, +{ + fn provide<'a>(&'a self, req: &mut Demand<'a>) { + self.provide(req) + } +} + +mod private { + // This is a hack to prevent `type_id` from being overridden by `Error` + // implementations, since that can enable unsound downcasting. + #[unstable(feature = "error_type_id", issue = "60784")] + #[derive(Debug)] + pub struct Internal; +} + +#[unstable(feature = "never_type", issue = "35121")] +impl Error for ! {} + +impl<'a> dyn Error + 'a { + /// Request a reference of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_ref(&'a self) -> Option<&'a T> { + core::any::request_ref(self) + } + + /// Request a value of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_value(&'a self) -> Option { + core::any::request_value(self) + } +} + +// Copied from `any.rs`. +impl dyn Error + 'static { + /// Returns `true` if the inner type is the same as `T`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn is(&self) -> bool { + // Get `TypeId` of the type this function is instantiated with. + let t = TypeId::of::(); + + // Get `TypeId` of the type in the trait object (`self`). + let concrete = self.type_id(private::Internal); + + // Compare both `TypeId`s on equality. + t == concrete + } + + /// Returns some reference to the inner value if it is of type `T`, or + /// `None` if it isn't. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_ref(&self) -> Option<&T> { + if self.is::() { + // SAFETY: `is` ensures this type cast is correct + unsafe { Some(&*(self as *const dyn Error as *const T)) } + } else { + None + } + } + + /// Returns some mutable reference to the inner value if it is of type `T`, or + /// `None` if it isn't. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_mut(&mut self) -> Option<&mut T> { + if self.is::() { + // SAFETY: `is` ensures this type cast is correct + unsafe { Some(&mut *(self as *mut dyn Error as *mut T)) } + } else { + None + } + } +} + +impl dyn Error + 'static + Send { + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn is(&self) -> bool { + ::is::(self) + } + + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_ref(&self) -> Option<&T> { + ::downcast_ref::(self) + } + + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_mut(&mut self) -> Option<&mut T> { + ::downcast_mut::(self) + } + + /// Request a reference of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_ref(&self) -> Option<&T> { + ::request_ref(self) + } + + /// Request a value of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_value(&self) -> Option { + ::request_value(self) + } +} + +impl dyn Error + 'static + Send + Sync { + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn is(&self) -> bool { + ::is::(self) + } + + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_ref(&self) -> Option<&T> { + ::downcast_ref::(self) + } + + /// Forwards to the method defined on the type `dyn Error`. + #[stable(feature = "error_downcast", since = "1.3.0")] + #[inline] + pub fn downcast_mut(&mut self) -> Option<&mut T> { + ::downcast_mut::(self) + } + + /// Request a reference of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_ref(&self) -> Option<&T> { + ::request_ref(self) + } + + /// Request a value of type `T` as context about this error. + #[unstable(feature = "error_generic_member_access", issue = "99301")] + pub fn request_value(&self) -> Option { + ::request_value(self) + } +} + +impl dyn Error { + /// Returns an iterator starting with the current error and continuing with + /// recursively calling [`Error::source`]. + /// + /// If you want to omit the current error and only use its sources, + /// use `skip(1)`. + /// + /// # Examples + /// + /// ``` + /// #![feature(error_iter)] + /// use std::error::Error; + /// use std::fmt; + /// + /// #[derive(Debug)] + /// struct A; + /// + /// #[derive(Debug)] + /// struct B(Option>); + /// + /// impl fmt::Display for A { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "A") + /// } + /// } + /// + /// impl fmt::Display for B { + /// fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + /// write!(f, "B") + /// } + /// } + /// + /// impl Error for A {} + /// + /// impl Error for B { + /// fn source(&self) -> Option<&(dyn Error + 'static)> { + /// self.0.as_ref().map(|e| e.as_ref()) + /// } + /// } + /// + /// let b = B(Some(Box::new(A))); + /// + /// // let err : Box = b.into(); // or + /// let err = &b as &(dyn Error); + /// + /// let mut iter = err.chain(); + /// + /// assert_eq!("B".to_string(), iter.next().unwrap().to_string()); + /// assert_eq!("A".to_string(), iter.next().unwrap().to_string()); + /// assert!(iter.next().is_none()); + /// assert!(iter.next().is_none()); + /// ``` + #[unstable(feature = "error_iter", issue = "58520")] + #[inline] + pub fn chain(&self) -> Chain<'_> { + Chain { current: Some(self) } + } +} + +/// An iterator over an [`Error`] and its sources. +/// +/// If you want to omit the initial error and only process +/// its sources, use `skip(1)`. +#[unstable(feature = "error_iter", issue = "58520")] +#[derive(Clone, Debug)] +pub struct Chain<'a> { + current: Option<&'a (dyn Error + 'static)>, +} + +#[unstable(feature = "error_iter", issue = "58520")] +impl<'a> Iterator for Chain<'a> { + type Item = &'a (dyn Error + 'static); + + fn next(&mut self) -> Option { + let current = self.current; + self.current = self.current.and_then(Error::source); + current + } +} + +#[stable(feature = "error_by_ref", since = "1.51.0")] +impl<'a, T: Error + ?Sized> Error for &'a T { + #[allow(deprecated, deprecated_in_future)] + fn description(&self) -> &str { + Error::description(&**self) + } + + #[allow(deprecated)] + fn cause(&self) -> Option<&dyn Error> { + Error::cause(&**self) + } + + fn source(&self) -> Option<&(dyn Error + 'static)> { + Error::source(&**self) + } + + fn provide<'b>(&'b self, req: &mut Demand<'b>) { + Error::provide(&**self, req); + } +} + +#[stable(feature = "fmt_error", since = "1.11.0")] +impl Error for crate::fmt::Error { + #[allow(deprecated)] + fn description(&self) -> &str { + "an error occurred when formatting an argument" + } +} + +#[stable(feature = "try_borrow", since = "1.13.0")] +impl Error for crate::cell::BorrowError { + #[allow(deprecated)] + fn description(&self) -> &str { + "already mutably borrowed" + } +} + +#[stable(feature = "try_borrow", since = "1.13.0")] +impl Error for crate::cell::BorrowMutError { + #[allow(deprecated)] + fn description(&self) -> &str { + "already borrowed" + } +} + +#[stable(feature = "try_from", since = "1.34.0")] +impl Error for crate::char::CharTryFromError { + #[allow(deprecated)] + fn description(&self) -> &str { + "converted integer out of range for `char`" + } +} + +#[stable(feature = "char_from_str", since = "1.20.0")] +impl Error for crate::char::ParseCharError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + +#[unstable(feature = "duration_checked_float", issue = "83400")] +impl Error for crate::time::FromFloatSecsError {} + +#[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] +impl Error for crate::ffi::FromBytesWithNulError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + +#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")] +impl Error for crate::ffi::FromBytesUntilNulError {} diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 24742bb49b9a5..8d04a213f503d 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -302,6 +302,8 @@ pub mod clone; pub mod cmp; pub mod convert; pub mod default; +#[cfg(not(bootstrap))] +pub mod error; pub mod marker; pub mod ops; diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs index 1a223016dae0f..1f6b40e5df554 100644 --- a/library/core/src/num/error.rs +++ b/library/core/src/num/error.rs @@ -1,6 +1,8 @@ //! Error types for conversion to integral types. use crate::convert::Infallible; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; /// The error type returned when a checked integral type conversion fails. @@ -144,3 +146,21 @@ impl fmt::Display for ParseIntError { self.__description().fmt(f) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for ParseIntError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + +#[cfg(not(bootstrap))] +#[stable(feature = "try_from", since = "1.34.0")] +impl Error for TryFromIntError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 72b6dc2818540..ab17aa0c83032 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -3,6 +3,8 @@ #![stable(feature = "rust1", since = "1.0.0")] use crate::ascii; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::intrinsics; use crate::mem; use crate::ops::{Add, Mul, Sub}; @@ -57,6 +59,16 @@ pub use wrapping::Wrapping; #[cfg(not(no_fp_fmt_parse))] pub use dec2flt::ParseFloatError; +#[cfg(not(bootstrap))] +#[cfg(not(no_fp_fmt_parse))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for ParseFloatError { + #[allow(deprecated)] + fn description(&self) -> &str { + self.__description() + } +} + #[stable(feature = "rust1", since = "1.0.0")] pub use error::ParseIntError; diff --git a/library/core/src/str/error.rs b/library/core/src/str/error.rs index 4e569fcc866b6..343889b6999fa 100644 --- a/library/core/src/str/error.rs +++ b/library/core/src/str/error.rs @@ -1,5 +1,7 @@ //! Defines utf8 error type. +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt; /// Errors which can occur when attempting to interpret a sequence of [`u8`] @@ -122,6 +124,15 @@ impl fmt::Display for Utf8Error { } } +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for Utf8Error { + #[allow(deprecated)] + fn description(&self) -> &str { + "invalid utf-8: corrupt contents" + } +} + /// An error returned when parsing a `bool` using [`from_str`] fails /// /// [`from_str`]: super::FromStr::from_str @@ -136,3 +147,12 @@ impl fmt::Display for ParseBoolError { "provided string was not `true` or `false`".fmt(f) } } + +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl Error for ParseBoolError { + #[allow(deprecated)] + fn description(&self) -> &str { + "failed to parse bool" + } +} diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index e44e025aaf169..2120bf61d759d 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -2638,3 +2638,7 @@ impl_fn_for_zst! { unsafe { from_utf8_unchecked(bytes) } }; } + +#[stable(feature = "rust1", since = "1.0.0")] +#[cfg(not(bootstrap))] +impl !crate::error::Error for &str {} diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index db811343fa322..9845d1faf9aa1 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -9,6 +9,8 @@ use crate::borrow::Borrow; use crate::cell::Cell; use crate::collections::TryReserveError; use crate::collections::TryReserveErrorKind; +#[cfg(not(bootstrap))] +use crate::error::Error; use crate::fmt::{self, Debug}; #[allow(deprecated)] use crate::hash::{BuildHasher, Hash, Hasher, SipHasher13}; @@ -2158,6 +2160,15 @@ impl<'a, K: Debug, V: Debug> fmt::Display for OccupiedError<'a, K, V> { } } +#[cfg(not(bootstrap))] +#[unstable(feature = "map_try_insert", issue = "82766")] +impl<'a, K: fmt::Debug, V: fmt::Debug> Error for OccupiedError<'a, K, V> { + #[allow(deprecated)] + fn description(&self) -> &str { + "key already exists" + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl<'a, K, V, S> IntoIterator for &'a HashMap { type Item = (&'a K, &'a V); diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 4fbcfd85d7c04..914f6d6d2e3e9 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -1,141 +1,4 @@ -//! The `Error` trait provides common functionality for errors. -//! -//! # Error Handling In Rust -//! -//! The Rust language provides two complementary systems for constructing / -//! representing, reporting, propagating, reacting to, and discarding errors. -//! These responsibilities are collectively known as "error handling." The -//! components of the first system, the panic runtime and interfaces, are most -//! commonly used to represent bugs that have been detected in your program. The -//! components of the second system, `Result`, the error traits, and user -//! defined types, are used to represent anticipated runtime failure modes of -//! your program. -//! -//! ## The Panic Interfaces -//! -//! The following are the primary interfaces of the panic system and the -//! responsibilities they cover: -//! -//! * [`panic!`] and [`panic_any`] (Constructing, Propagated automatically) -//! * [`PanicInfo`] (Reporting) -//! * [`set_hook`], [`take_hook`], and [`#[panic_handler]`][panic-handler] (Reporting) -//! * [`catch_unwind`] and [`resume_unwind`] (Discarding, Propagating) -//! -//! The following are the primary interfaces of the error system and the -//! responsibilities they cover: -//! -//! * [`Result`] (Propagating, Reacting) -//! * The [`Error`] trait (Reporting) -//! * User defined types (Constructing / Representing) -//! * [`match`] and [`downcast`] (Reacting) -//! * The question mark operator ([`?`]) (Propagating) -//! * The partially stable [`Try`] traits (Propagating, Constructing) -//! * [`Termination`] (Reporting) -//! -//! ## Converting Errors into Panics -//! -//! The panic and error systems are not entirely distinct. Often times errors -//! that are anticipated runtime failures in an API might instead represent bugs -//! to a caller. For these situations the standard library provides APIs for -//! constructing panics with an `Error` as it's source. -//! -//! * [`Result::unwrap`] -//! * [`Result::expect`] -//! -//! These functions are equivalent, they either return the inner value if the -//! `Result` is `Ok` or panic if the `Result` is `Err` printing the inner error -//! as the source. The only difference between them is that with `expect` you -//! provide a panic error message to be printed alongside the source, whereas -//! `unwrap` has a default message indicating only that you unwraped an `Err`. -//! -//! Of the two, `expect` is generally preferred since its `msg` field allows you -//! to convey your intent and assumptions which makes tracking down the source -//! of a panic easier. `unwrap` on the other hand can still be a good fit in -//! situations where you can trivially show that a piece of code will never -//! panic, such as `"127.0.0.1".parse::().unwrap()` or early -//! prototyping. -//! -//! # Common Message Styles -//! -//! There are two common styles for how people word `expect` messages. Using -//! the message to present information to users encountering a panic -//! ("expect as error message") or using the message to present information -//! to developers debugging the panic ("expect as precondition"). -//! -//! In the former case the expect message is used to describe the error that -//! has occurred which is considered a bug. Consider the following example: -//! -//! ```should_panic -//! // Read environment variable, panic if it is not present -//! let path = std::env::var("IMPORTANT_PATH").unwrap(); -//! ``` -//! -//! In the "expect as error message" style we would use expect to describe -//! that the environment variable was not set when it should have been: -//! -//! ```should_panic -//! let path = std::env::var("IMPORTANT_PATH") -//! .expect("env variable `IMPORTANT_PATH` is not set"); -//! ``` -//! -//! In the "expect as precondition" style, we would instead describe the -//! reason we _expect_ the `Result` should be `Ok`. With this style we would -//! prefer to write: -//! -//! ```should_panic -//! let path = std::env::var("IMPORTANT_PATH") -//! .expect("env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`"); -//! ``` -//! -//! The "expect as error message" style does not work as well with the -//! default output of the std panic hooks, and often ends up repeating -//! information that is already communicated by the source error being -//! unwrapped: -//! -//! ```text -//! thread 'main' panicked at 'env variable `IMPORTANT_PATH` is not set: NotPresent', src/main.rs:4:6 -//! ``` -//! -//! In this example we end up mentioning that an env variable is not set, -//! followed by our source message that says the env is not present, the -//! only additional information we're communicating is the name of the -//! environment variable being checked. -//! -//! The "expect as precondition" style instead focuses on source code -//! readability, making it easier to understand what must have gone wrong in -//! situations where panics are being used to represent bugs exclusively. -//! Also, by framing our expect in terms of what "SHOULD" have happened to -//! prevent the source error, we end up introducing new information that is -//! independent from our source error. -//! -//! ```text -//! thread 'main' panicked at 'env variable `IMPORTANT_PATH` should be set by `wrapper_script.sh`: NotPresent', src/main.rs:4:6 -//! ``` -//! -//! In this example we are communicating not only the name of the -//! environment variable that should have been set, but also an explanation -//! for why it should have been set, and we let the source error display as -//! a clear contradiction to our expectation. -//! -//! **Hint**: If you're having trouble remembering how to phrase -//! expect-as-precondition style error messages remember to focus on the word -//! "should" as in "env variable should be set by blah" or "the given binary -//! should be available and executable by the current user". -//! -//! [`panic_any`]: crate::panic::panic_any -//! [`PanicInfo`]: crate::panic::PanicInfo -//! [`catch_unwind`]: crate::panic::catch_unwind -//! [`resume_unwind`]: crate::panic::resume_unwind -//! [`downcast`]: crate::error::Error -//! [`Termination`]: crate::process::Termination -//! [`Try`]: crate::ops::Try -//! [panic hook]: crate::panic::set_hook -//! [`set_hook`]: crate::panic::set_hook -//! [`take_hook`]: crate::panic::take_hook -//! [panic-handler]: -//! [`match`]: ../../std/keyword.match.html -//! [`?`]: ../../std/result/index.html#the-question-mark-operator- - +#![doc = include_str!("../../core/src/error.md")] #![stable(feature = "rust1", since = "1.0.0")] // A note about crates and the facade: @@ -152,24 +15,48 @@ #[cfg(test)] mod tests; +#[cfg(bootstrap)] use core::array; +#[cfg(bootstrap)] use core::convert::Infallible; +#[cfg(bootstrap)] use crate::alloc::{AllocError, LayoutError}; -use crate::any::{Demand, Provider, TypeId}; +#[cfg(bootstrap)] +use crate::any::Demand; +#[cfg(bootstrap)] +use crate::any::{Provider, TypeId}; use crate::backtrace::Backtrace; +#[cfg(bootstrap)] use crate::borrow::Cow; +#[cfg(bootstrap)] use crate::cell; +#[cfg(bootstrap)] use crate::char; -use crate::fmt::{self, Debug, Display, Write}; +#[cfg(bootstrap)] +use crate::fmt::Debug; +#[cfg(bootstrap)] +use crate::fmt::Display; +use crate::fmt::{self, Write}; +#[cfg(bootstrap)] use crate::io; +#[cfg(bootstrap)] use crate::mem::transmute; +#[cfg(bootstrap)] use crate::num; +#[cfg(bootstrap)] use crate::str; +#[cfg(bootstrap)] use crate::string; +#[cfg(bootstrap)] use crate::sync::Arc; +#[cfg(bootstrap)] use crate::time; +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +pub use core::error::Error; + /// `Error` is a trait representing the basic expectations for error values, /// i.e., values of type `E` in [`Result`]. /// @@ -190,6 +77,7 @@ use crate::time; /// implementation for debugging via `source` chains. #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "Error")] +#[cfg(bootstrap)] pub trait Error: Debug + Display { /// The lower-level source of this error, if any. /// @@ -355,6 +243,7 @@ pub trait Error: Debug + Display { fn provide<'a>(&'a self, req: &mut Demand<'a>) {} } +#[cfg(bootstrap)] #[unstable(feature = "error_generic_member_access", issue = "99301")] impl<'b> Provider for dyn Error + 'b { fn provide<'a>(&'a self, req: &mut Demand<'a>) { @@ -370,6 +259,7 @@ mod private { pub struct Internal; } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl<'a, E: Error + 'a> From for Box { /// Converts a type of [`Error`] into a box of dyn [`Error`]. @@ -402,6 +292,7 @@ impl<'a, E: Error + 'a> From for Box { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl<'a, E: Error + Send + Sync + 'a> From for Box { /// Converts a type of [`Error`] + [`Send`] + [`Sync`] into a box of @@ -440,6 +331,7 @@ impl<'a, E: Error + Send + Sync + 'a> From for Box for Box { /// Converts a [`String`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. @@ -483,6 +375,7 @@ impl From for Box { } } +#[cfg(bootstrap)] #[stable(feature = "string_box_error", since = "1.6.0")] impl From for Box { /// Converts a [`String`] into a box of dyn [`Error`]. @@ -504,6 +397,7 @@ impl From for Box { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl<'a> From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. @@ -527,6 +421,7 @@ impl<'a> From<&str> for Box { } } +#[cfg(bootstrap)] #[stable(feature = "string_box_error", since = "1.6.0")] impl From<&str> for Box { /// Converts a [`str`] into a box of dyn [`Error`]. @@ -548,6 +443,7 @@ impl From<&str> for Box { } } +#[cfg(bootstrap)] #[stable(feature = "cow_box_error", since = "1.22.0")] impl<'a, 'b> From> for Box { /// Converts a [`Cow`] into a box of dyn [`Error`] + [`Send`] + [`Sync`]. @@ -569,6 +465,7 @@ impl<'a, 'b> From> for Box { } } +#[cfg(bootstrap)] #[stable(feature = "cow_box_error", since = "1.22.0")] impl<'a> From> for Box { /// Converts a [`Cow`] into a box of dyn [`Error`]. @@ -589,9 +486,11 @@ impl<'a> From> for Box { } } +#[cfg(bootstrap)] #[unstable(feature = "never_type", issue = "35121")] impl Error for ! {} +#[cfg(bootstrap)] #[unstable( feature = "allocator_api", reason = "the precise API and guarantees it provides may be tweaked.", @@ -599,9 +498,11 @@ impl Error for ! {} )] impl Error for AllocError {} +#[cfg(bootstrap)] #[stable(feature = "alloc_layout", since = "1.28.0")] impl Error for LayoutError {} +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for str::ParseBoolError { #[allow(deprecated)] @@ -610,6 +511,7 @@ impl Error for str::ParseBoolError { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for str::Utf8Error { #[allow(deprecated)] @@ -618,6 +520,7 @@ impl Error for str::Utf8Error { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for num::ParseIntError { #[allow(deprecated)] @@ -626,6 +529,7 @@ impl Error for num::ParseIntError { } } +#[cfg(bootstrap)] #[stable(feature = "try_from", since = "1.34.0")] impl Error for num::TryFromIntError { #[allow(deprecated)] @@ -634,6 +538,7 @@ impl Error for num::TryFromIntError { } } +#[cfg(bootstrap)] #[stable(feature = "try_from", since = "1.34.0")] impl Error for array::TryFromSliceError { #[allow(deprecated)] @@ -642,6 +547,7 @@ impl Error for array::TryFromSliceError { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for num::ParseFloatError { #[allow(deprecated)] @@ -650,6 +556,7 @@ impl Error for num::ParseFloatError { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for string::FromUtf8Error { #[allow(deprecated)] @@ -658,6 +565,7 @@ impl Error for string::FromUtf8Error { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for string::FromUtf16Error { #[allow(deprecated)] @@ -666,6 +574,7 @@ impl Error for string::FromUtf16Error { } } +#[cfg(bootstrap)] #[stable(feature = "str_parse_error2", since = "1.8.0")] impl Error for Infallible { fn description(&self) -> &str { @@ -673,6 +582,7 @@ impl Error for Infallible { } } +#[cfg(bootstrap)] #[stable(feature = "decode_utf16", since = "1.9.0")] impl Error for char::DecodeUtf16Error { #[allow(deprecated)] @@ -681,9 +591,11 @@ impl Error for char::DecodeUtf16Error { } } +#[cfg(bootstrap)] #[stable(feature = "u8_from_char", since = "1.59.0")] impl Error for char::TryFromCharError {} +#[cfg(bootstrap)] #[unstable(feature = "map_try_insert", issue = "82766")] impl<'a, K: Debug + Ord, V: Debug> Error for crate::collections::btree_map::OccupiedError<'a, K, V> @@ -694,6 +606,7 @@ impl<'a, K: Debug + Ord, V: Debug> Error } } +#[cfg(bootstrap)] #[unstable(feature = "map_try_insert", issue = "82766")] impl<'a, K: Debug, V: Debug> Error for crate::collections::hash_map::OccupiedError<'a, K, V> { #[allow(deprecated)] @@ -702,6 +615,7 @@ impl<'a, K: Debug, V: Debug> Error for crate::collections::hash_map::OccupiedErr } } +#[cfg(bootstrap)] #[stable(feature = "box_error", since = "1.8.0")] impl Error for Box { #[allow(deprecated, deprecated_in_future)] @@ -719,6 +633,7 @@ impl Error for Box { } } +#[cfg(bootstrap)] #[unstable(feature = "thin_box", issue = "92791")] impl crate::error::Error for crate::boxed::ThinBox { fn source(&self) -> Option<&(dyn crate::error::Error + 'static)> { @@ -727,6 +642,7 @@ impl crate::error::Error for crate::boxed::Thin } } +#[cfg(bootstrap)] #[stable(feature = "error_by_ref", since = "1.51.0")] impl<'a, T: Error + ?Sized> Error for &'a T { #[allow(deprecated, deprecated_in_future)] @@ -748,6 +664,7 @@ impl<'a, T: Error + ?Sized> Error for &'a T { } } +#[cfg(bootstrap)] #[stable(feature = "arc_error", since = "1.52.0")] impl Error for Arc { #[allow(deprecated, deprecated_in_future)] @@ -769,6 +686,7 @@ impl Error for Arc { } } +#[cfg(bootstrap)] #[stable(feature = "fmt_error", since = "1.11.0")] impl Error for fmt::Error { #[allow(deprecated)] @@ -777,6 +695,7 @@ impl Error for fmt::Error { } } +#[cfg(bootstrap)] #[stable(feature = "try_borrow", since = "1.13.0")] impl Error for cell::BorrowError { #[allow(deprecated)] @@ -785,6 +704,7 @@ impl Error for cell::BorrowError { } } +#[cfg(bootstrap)] #[stable(feature = "try_borrow", since = "1.13.0")] impl Error for cell::BorrowMutError { #[allow(deprecated)] @@ -793,6 +713,7 @@ impl Error for cell::BorrowMutError { } } +#[cfg(bootstrap)] #[stable(feature = "try_from", since = "1.34.0")] impl Error for char::CharTryFromError { #[allow(deprecated)] @@ -801,6 +722,7 @@ impl Error for char::CharTryFromError { } } +#[cfg(bootstrap)] #[stable(feature = "char_from_str", since = "1.20.0")] impl Error for char::ParseCharError { #[allow(deprecated)] @@ -809,12 +731,15 @@ impl Error for char::ParseCharError { } } +#[cfg(bootstrap)] #[stable(feature = "try_reserve", since = "1.57.0")] impl Error for alloc::collections::TryReserveError {} +#[cfg(bootstrap)] #[unstable(feature = "duration_checked_float", issue = "83400")] impl Error for time::FromFloatSecsError {} +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl Error for alloc::ffi::NulError { #[allow(deprecated)] @@ -823,6 +748,7 @@ impl Error for alloc::ffi::NulError { } } +#[cfg(bootstrap)] #[stable(feature = "rust1", since = "1.0.0")] impl From for io::Error { /// Converts a [`alloc::ffi::NulError`] into a [`io::Error`]. @@ -831,6 +757,7 @@ impl From for io::Error { } } +#[cfg(bootstrap)] #[stable(feature = "frombyteswithnulerror_impls", since = "1.17.0")] impl Error for core::ffi::FromBytesWithNulError { #[allow(deprecated)] @@ -839,12 +766,15 @@ impl Error for core::ffi::FromBytesWithNulError { } } +#[cfg(bootstrap)] #[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")] impl Error for core::ffi::FromBytesUntilNulError {} +#[cfg(bootstrap)] #[stable(feature = "cstring_from_vec_with_nul", since = "1.58.0")] impl Error for alloc::ffi::FromVecWithNulError {} +#[cfg(bootstrap)] #[stable(feature = "cstring_into", since = "1.7.0")] impl Error for alloc::ffi::IntoStringError { #[allow(deprecated)] @@ -857,6 +787,7 @@ impl Error for alloc::ffi::IntoStringError { } } +#[cfg(bootstrap)] impl<'a> dyn Error + 'a { /// Request a reference of type `T` as context about this error. #[unstable(feature = "error_generic_member_access", issue = "99301")] @@ -872,6 +803,7 @@ impl<'a> dyn Error + 'a { } // Copied from `any.rs`. +#[cfg(bootstrap)] impl dyn Error + 'static { /// Returns `true` if the inner type is the same as `T`. #[stable(feature = "error_downcast", since = "1.3.0")] @@ -912,6 +844,7 @@ impl dyn Error + 'static { } } +#[cfg(bootstrap)] impl dyn Error + 'static + Send { /// Forwards to the method defined on the type `dyn Error`. #[stable(feature = "error_downcast", since = "1.3.0")] @@ -947,6 +880,7 @@ impl dyn Error + 'static + Send { } } +#[cfg(bootstrap)] impl dyn Error + 'static + Send + Sync { /// Forwards to the method defined on the type `dyn Error`. #[stable(feature = "error_downcast", since = "1.3.0")] @@ -982,6 +916,7 @@ impl dyn Error + 'static + Send + Sync { } } +#[cfg(bootstrap)] impl dyn Error { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] @@ -1061,10 +996,12 @@ impl dyn Error { /// its sources, use `skip(1)`. #[unstable(feature = "error_iter", issue = "58520")] #[derive(Clone, Debug)] +#[cfg(bootstrap)] pub struct Chain<'a> { current: Option<&'a (dyn Error + 'static)>, } +#[cfg(bootstrap)] #[unstable(feature = "error_iter", issue = "58520")] impl<'a> Iterator for Chain<'a> { type Item = &'a (dyn Error + 'static); @@ -1076,6 +1013,7 @@ impl<'a> Iterator for Chain<'a> { } } +#[cfg(bootstrap)] impl dyn Error + Send { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] @@ -1089,6 +1027,7 @@ impl dyn Error + Send { } } +#[cfg(bootstrap)] impl dyn Error + Send + Sync { #[inline] #[stable(feature = "error_downcast", since = "1.3.0")] @@ -1246,7 +1185,7 @@ impl dyn Error + Send + Sync { /// # Err(SuperError { source: SuperErrorSideKick }) /// # } /// -/// fn main() -> Result<(), Report> { +/// fn main() -> Result<(), Report> { /// get_super_error()?; /// Ok(()) /// } @@ -1293,7 +1232,7 @@ impl dyn Error + Send + Sync { /// # Err(SuperError { source: SuperErrorSideKick }) /// # } /// -/// fn main() -> Result<(), Report> { +/// fn main() -> Result<(), Report> { /// get_super_error() /// .map_err(Report::from) /// .map_err(|r| r.pretty(true).show_backtrace(true))?; @@ -1605,72 +1544,6 @@ where } } -impl Report> { - fn backtrace(&self) -> Option<&Backtrace> { - // have to grab the backtrace on the first error directly since that error may not be - // 'static - let backtrace = self.error.request_ref(); - let backtrace = backtrace.or_else(|| { - self.error - .source() - .map(|source| source.chain().find_map(|source| source.request_ref())) - .flatten() - }); - backtrace - } - - /// Format the report as a single line. - #[unstable(feature = "error_reporter", issue = "90172")] - fn fmt_singleline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.error)?; - - let sources = self.error.source().into_iter().flat_map(::chain); - - for cause in sources { - write!(f, ": {cause}")?; - } - - Ok(()) - } - - /// Format the report as multiple lines, with each error cause on its own line. - #[unstable(feature = "error_reporter", issue = "90172")] - fn fmt_multiline(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let error = &self.error; - - write!(f, "{error}")?; - - if let Some(cause) = error.source() { - write!(f, "\n\nCaused by:")?; - - let multiple = cause.source().is_some(); - - for (ind, error) in cause.chain().enumerate() { - writeln!(f)?; - let mut indented = Indented { inner: f }; - if multiple { - write!(indented, "{ind: >4}: {error}")?; - } else { - write!(indented, " {error}")?; - } - } - } - - if self.show_backtrace { - let backtrace = self.backtrace(); - - if let Some(backtrace) = backtrace { - let backtrace = backtrace.to_string(); - - f.write_str("\n\nStack backtrace:\n")?; - f.write_str(backtrace.trim_end())?; - } - } - - Ok(()) - } -} - #[unstable(feature = "error_reporter", issue = "90172")] impl From for Report where @@ -1681,17 +1554,6 @@ where } } -#[unstable(feature = "error_reporter", issue = "90172")] -impl<'a, E> From for Report> -where - E: Error + 'a, -{ - fn from(error: E) -> Self { - let error = box error; - Report { error, show_backtrace: false, pretty: false } - } -} - #[unstable(feature = "error_reporter", issue = "90172")] impl fmt::Display for Report where @@ -1702,13 +1564,6 @@ where } } -#[unstable(feature = "error_reporter", issue = "90172")] -impl fmt::Display for Report> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if self.pretty { self.fmt_multiline(f) } else { self.fmt_singleline(f) } - } -} - // This type intentionally outputs the same format for `Display` and `Debug`for // situations where you unwrap a `Report` or return it from main. #[unstable(feature = "error_reporter", issue = "90172")] diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index ff7fdcae16f53..885e44f5e18bd 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -76,6 +76,15 @@ impl fmt::Debug for Error { } } +#[cfg(not(bootstrap))] +#[stable(feature = "rust1", since = "1.0.0")] +impl From for Error { + /// Converts a [`alloc::ffi::NulError`] into a [`Error`]. + fn from(_: alloc::ffi::NulError) -> Error { + const_io_error!(ErrorKind::InvalidInput, "data provided contains a nul byte") + } +} + // Only derive debug in tests, to make sure it // doesn't accidentally get printed. #[cfg_attr(test, derive(Debug))] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 5029023121fc2..1f23c98618b9f 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -281,6 +281,9 @@ #![feature(cstr_internals)] #![feature(duration_checked_float)] #![feature(duration_constants)] +#![cfg_attr(not(bootstrap), feature(error_generic_member_access))] +#![cfg_attr(not(bootstrap), feature(error_in_core))] +#![cfg_attr(not(bootstrap), feature(error_iter))] #![feature(exact_size_is_empty)] #![feature(exclusive_wrapper)] #![feature(extend_one)] From d7d701a9dc6c424e01d49d937925dc3bf7718138 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 14 Jul 2022 14:54:53 +0200 Subject: [PATCH 07/13] Create specific ConstantHasGenerics for ConstantItemRibKind. --- compiler/rustc_resolve/src/diagnostics.rs | 2 +- compiler/rustc_resolve/src/ident.rs | 12 ++++++-- compiler/rustc_resolve/src/late.rs | 35 ++++++++++++++--------- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 325b0458638af..193610ff57d55 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -550,7 +550,7 @@ impl<'a> Resolver<'a> { } } - if has_generic_params == HasGenericParams::Yes { + if let HasGenericParams::Yes = has_generic_params { // Try to retrieve the span of the function signature and generate a new // message with a local type or const parameter. let sugg_msg = "try using a local generic parameter instead"; diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 6e6782881427b..be50eecf4b128 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -13,7 +13,9 @@ use rustc_span::{Span, DUMMY_SP}; use std::ptr; -use crate::late::{ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind}; +use crate::late::{ + ConstantHasGenerics, ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind, +}; use crate::macros::{sub_namespace_match, MacroRulesScope}; use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize}; use crate::{ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot}; @@ -1180,7 +1182,9 @@ impl<'a> Resolver<'a> { ConstantItemRibKind(trivial, _) => { let features = self.session.features_untracked(); // HACK(min_const_generics): We currently only allow `N` or `{ N }`. - if !(trivial == HasGenericParams::Yes || features.generic_const_exprs) { + if !(trivial == ConstantHasGenerics::Yes + || features.generic_const_exprs) + { // HACK(min_const_generics): If we encounter `Self` in an anonymous constant // we can't easily tell if it's generic at this stage, so we instead remember // this and then enforce the self type to be concrete later on. @@ -1253,7 +1257,9 @@ impl<'a> Resolver<'a> { ConstantItemRibKind(trivial, _) => { let features = self.session.features_untracked(); // HACK(min_const_generics): We currently only allow `N` or `{ N }`. - if !(trivial == HasGenericParams::Yes || features.generic_const_exprs) { + if !(trivial == ConstantHasGenerics::Yes + || features.generic_const_exprs) + { if let Some(span) = finalize { self.report_error( span, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 58a4cff55db7d..b6fedd838bb33 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -91,13 +91,20 @@ enum PatBoundCtx { } /// Does this the item (from the item rib scope) allow generic parameters? -#[derive(Copy, Clone, Debug, Eq, PartialEq)] +#[derive(Copy, Clone, Debug)] pub(crate) enum HasGenericParams { Yes, No, } -impl HasGenericParams { +/// May this constant have generics? +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub(crate) enum ConstantHasGenerics { + Yes, + No, +} + +impl ConstantHasGenerics { fn force_yes_if(self, b: bool) -> Self { if b { Self::Yes } else { self } } @@ -136,7 +143,7 @@ pub(crate) enum RibKind<'a> { /// /// The item may reference generic parameters in trivial constant expressions. /// All other constants aren't allowed to use generic params at all. - ConstantItemRibKind(HasGenericParams, Option<(Ident, ConstantItemKind)>), + ConstantItemRibKind(ConstantHasGenerics, Option<(Ident, ConstantItemKind)>), /// We passed through a module. ModuleRibKind(Module<'a>), @@ -995,7 +1002,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { // non-trivial constants this is doesn't matter. self.with_constant_rib( IsRepeatExpr::No, - HasGenericParams::Yes, + ConstantHasGenerics::Yes, None, |this| { this.smart_resolve_path( @@ -2251,7 +2258,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // so it doesn't matter whether this is a trivial constant. this.with_constant_rib( IsRepeatExpr::No, - HasGenericParams::Yes, + ConstantHasGenerics::Yes, Some((item.ident, constant_item_kind)), |this| this.visit_expr(expr), ); @@ -2450,7 +2457,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn with_constant_rib( &mut self, is_repeat: IsRepeatExpr, - may_use_generics: HasGenericParams, + may_use_generics: ConstantHasGenerics, item: Option<(Ident, ConstantItemKind)>, f: impl FnOnce(&mut Self), ) { @@ -2517,7 +2524,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { |this| { this.with_constant_rib( IsRepeatExpr::No, - HasGenericParams::Yes, + ConstantHasGenerics::Yes, None, |this| this.visit_expr(expr), ) @@ -2689,7 +2696,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| { this.with_constant_rib( IsRepeatExpr::No, - HasGenericParams::Yes, + ConstantHasGenerics::Yes, None, |this| this.visit_expr(expr), ) @@ -3696,9 +3703,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_constant_rib( is_repeat, if constant.value.is_potential_trivial_const_param() { - HasGenericParams::Yes + ConstantHasGenerics::Yes } else { - HasGenericParams::No + ConstantHasGenerics::No }, None, |this| visit::walk_anon_const(this, constant), @@ -3707,8 +3714,8 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn resolve_inline_const(&mut self, constant: &'ast AnonConst) { debug!("resolve_anon_const {constant:?}"); - self.with_constant_rib(IsRepeatExpr::No, HasGenericParams::Yes, None, |this| { - visit::walk_anon_const(this, constant); + self.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, None, |this| { + visit::walk_anon_const(this, constant) }); } @@ -3814,9 +3821,9 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_constant_rib( IsRepeatExpr::No, if argument.is_potential_trivial_const_param() { - HasGenericParams::Yes + ConstantHasGenerics::Yes } else { - HasGenericParams::No + ConstantHasGenerics::No }, None, |this| { From 613dc2204dc628e6804b9d2be8bdeb6f6f43611e Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 14 Jul 2022 15:09:30 +0200 Subject: [PATCH 08/13] Improve local generic parameter suggestions. --- compiler/rustc_resolve/src/diagnostics.rs | 33 +++++++++---------- compiler/rustc_resolve/src/ident.rs | 8 ++--- compiler/rustc_resolve/src/late.rs | 18 +++++----- compiler/rustc_resolve/src/lib.rs | 10 ++++++ compiler/rustc_span/src/symbol.rs | 1 + .../early/const-param-from-outer-fn.stderr | 2 +- src/test/ui/error-codes/E0401.stderr | 8 ++--- src/test/ui/generics/issue-98432.stderr | 6 ++-- src/test/ui/issues/issue-3214.stderr | 5 ++- src/test/ui/issues/issue-5997-enum.stderr | 8 ++--- src/test/ui/issues/issue-5997-struct.stderr | 8 ++--- src/test/ui/nested-ty-params.stderr | 12 +++---- .../ui/resolve/bad-type-env-capture.stderr | 6 ++-- src/test/ui/resolve/issue-3021-c.stderr | 16 ++++----- ...resolve-type-param-in-item-in-trait.stderr | 18 +++++----- src/test/ui/type/type-arg-out-of-scope.stderr | 12 +++---- 16 files changed, 90 insertions(+), 81 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 193610ff57d55..fc19835019881 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -511,7 +511,7 @@ impl<'a> Resolver<'a> { err.span_label(span, "use of generic parameter from outer function"); let sm = self.session.source_map(); - match outer_res { + let def_id = match outer_res { Res::SelfTy { trait_: maybe_trait_defid, alias_to: maybe_impl_defid } => { if let Some(impl_span) = maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id)) @@ -536,11 +536,13 @@ impl<'a> Resolver<'a> { if let Some(span) = self.opt_span(def_id) { err.span_label(span, "type parameter from outer function"); } + def_id } Res::Def(DefKind::ConstParam, def_id) => { if let Some(span) = self.opt_span(def_id) { err.span_label(span, "const parameter from outer function"); } + def_id } _ => { bug!( @@ -548,28 +550,23 @@ impl<'a> Resolver<'a> { DefKind::TyParam or DefKind::ConstParam" ); } - } + }; - if let HasGenericParams::Yes = has_generic_params { + if let HasGenericParams::Yes(span) = has_generic_params { // Try to retrieve the span of the function signature and generate a new // message with a local type or const parameter. let sugg_msg = "try using a local generic parameter instead"; - if let Some((sugg_span, snippet)) = sm.generate_local_type_param_snippet(span) { - // Suggest the modification to the user - err.span_suggestion( - sugg_span, - sugg_msg, - snippet, - Applicability::MachineApplicable, - ); - } else if let Some(sp) = sm.generate_fn_name_span(span) { - err.span_label( - sp, - "try adding a local generic parameter in this method instead", - ); + let name = self.opt_name(def_id).unwrap_or(sym::T); + let (span, snippet) = if span.is_empty() { + let snippet = format!("<{}>", name); + (span, snippet) } else { - err.help("try using a local generic parameter instead"); - } + let span = sm.span_through_char(span, '<').shrink_to_hi(); + let snippet = format!("{}, ", name); + (span, snippet) + }; + // Suggest the modification to the user + err.span_suggestion(span, sugg_msg, snippet, Applicability::MachineApplicable); } err diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index be50eecf4b128..0d8f1cf365643 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1170,10 +1170,11 @@ impl<'a> Resolver<'a> { let has_generic_params: HasGenericParams = match rib.kind { NormalRibKind | ClosureOrAsyncRibKind - | AssocItemRibKind | ModuleRibKind(..) | MacroDefinition(..) | InlineAsmSymRibKind + | FnItemRibKind + | AssocItemRibKind | ForwardGenericParamBanRibKind => { // Nothing to do. Continue. continue; @@ -1211,7 +1212,6 @@ impl<'a> Resolver<'a> { // This was an attempt to use a type parameter outside its scope. ItemRibKind(has_generic_params) => has_generic_params, - FnItemRibKind => HasGenericParams::Yes, ConstParamTyRibKind => { if let Some(span) = finalize { self.report_error( @@ -1248,10 +1248,11 @@ impl<'a> Resolver<'a> { let has_generic_params = match rib.kind { NormalRibKind | ClosureOrAsyncRibKind - | AssocItemRibKind | ModuleRibKind(..) | MacroDefinition(..) | InlineAsmSymRibKind + | FnItemRibKind + | AssocItemRibKind | ForwardGenericParamBanRibKind => continue, ConstantItemRibKind(trivial, _) => { @@ -1278,7 +1279,6 @@ impl<'a> Resolver<'a> { } ItemRibKind(has_generic_params) => has_generic_params, - FnItemRibKind => HasGenericParams::Yes, ConstParamTyRibKind => { if let Some(span) = finalize { self.report_error( diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index b6fedd838bb33..748a0781c4f7a 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -93,7 +93,7 @@ enum PatBoundCtx { /// Does this the item (from the item rib scope) allow generic parameters? #[derive(Copy, Clone, Debug)] pub(crate) enum HasGenericParams { - Yes, + Yes(Span), No, } @@ -758,7 +758,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.with_lifetime_rib(LifetimeRibKind::Item, |this| { this.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: foreign_item.id, kind: LifetimeBinderKind::Item, @@ -772,7 +772,7 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { self.with_lifetime_rib(LifetimeRibKind::Item, |this| { this.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: foreign_item.id, kind: LifetimeBinderKind::Function, @@ -2078,7 +2078,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_current_self_item(item, |this| { this.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2148,7 +2148,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ItemKind::TyAlias(box TyAlias { ref generics, .. }) => { self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2161,7 +2161,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ItemKind::Fn(box Fn { ref generics, .. }) => { self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Function, @@ -2193,7 +2193,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2217,7 +2217,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Create a new rib for the trait-wide type parameters. self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { binder: item.id, kind: LifetimeBinderKind::Item, @@ -2605,7 +2605,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // If applicable, create a rib for the type parameters. self.with_generic_param_rib( &generics.params, - ItemRibKind(HasGenericParams::Yes), + ItemRibKind(HasGenericParams::Yes(generics.span)), LifetimeRibKind::Generics { span: generics.span, binder: item_id, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 9c213da8c2a2c..eb727debc91bb 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -1945,6 +1945,16 @@ impl<'a> Resolver<'a> { def_id.as_local().map(|def_id| self.source_span[def_id]) } + /// Retrieves the name of the given `DefId`. + #[inline] + pub fn opt_name(&self, def_id: DefId) -> Option { + let def_key = match def_id.as_local() { + Some(def_id) => self.definitions.def_key(def_id), + None => self.cstore().def_key(def_id), + }; + def_key.get_opt_name() + } + /// Checks if an expression refers to a function marked with /// `#[rustc_legacy_const_generics]` and returns the argument index list /// from the attribute. diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 156f53ac48626..c8978845ffb0d 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -280,6 +280,7 @@ symbols! { StructuralPartialEq, SubdiagnosticMessage, Sync, + T, Target, ToOwned, ToString, diff --git a/src/test/ui/const-generics/early/const-param-from-outer-fn.stderr b/src/test/ui/const-generics/early/const-param-from-outer-fn.stderr index a9f9787d87595..e3bf38b702e75 100644 --- a/src/test/ui/const-generics/early/const-param-from-outer-fn.stderr +++ b/src/test/ui/const-generics/early/const-param-from-outer-fn.stderr @@ -4,7 +4,7 @@ error[E0401]: can't use generic parameters from outer function LL | fn foo() { | - const parameter from outer function LL | fn bar() -> u32 { - | --- try adding a local generic parameter in this method instead + | - help: try using a local generic parameter instead: `` LL | X | ^ use of generic parameter from outer function diff --git a/src/test/ui/error-codes/E0401.stderr b/src/test/ui/error-codes/E0401.stderr index 81715621dd921..b0e2ef5b6f7e3 100644 --- a/src/test/ui/error-codes/E0401.stderr +++ b/src/test/ui/error-codes/E0401.stderr @@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function LL | fn foo(x: T) { | - type parameter from outer function LL | fn bfnr, W: Fn()>(y: T) { - | --------------------------- ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `bfnr, W: Fn(), T>` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `T,` error[E0401]: can't use generic parameters from outer function --> $DIR/E0401.rs:9:16 @@ -15,7 +15,7 @@ LL | fn foo(x: T) { | - type parameter from outer function ... LL | fn baz Struct { | - type parameter from outer function LL | const CONST: fn() = || { LL | struct _Obligation where T:; - | ^ use of generic parameter from outer function - | - = help: try using a local generic parameter instead + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3214.stderr b/src/test/ui/issues/issue-3214.stderr index 4d8eb6360e640..aa0b5ce64b421 100644 --- a/src/test/ui/issues/issue-3214.stderr +++ b/src/test/ui/issues/issue-3214.stderr @@ -2,10 +2,9 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/issue-3214.rs:3:12 | LL | fn foo() { - | --- - type parameter from outer function - | | - | try adding a local generic parameter in this method instead + | - type parameter from outer function LL | struct Foo { + | - help: try using a local generic parameter instead: `` LL | x: T, | ^ use of generic parameter from outer function diff --git a/src/test/ui/issues/issue-5997-enum.stderr b/src/test/ui/issues/issue-5997-enum.stderr index 1c58b9c391104..3a79215d3ae9c 100644 --- a/src/test/ui/issues/issue-5997-enum.stderr +++ b/src/test/ui/issues/issue-5997-enum.stderr @@ -2,11 +2,11 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/issue-5997-enum.rs:2:16 | LL | fn f() -> bool { - | - - type parameter from outer function - | | - | try adding a local generic parameter in this method instead + | - type parameter from outer function LL | enum E { V(Z) } - | ^ use of generic parameter from outer function + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-5997-struct.stderr b/src/test/ui/issues/issue-5997-struct.stderr index 5b388d16d7553..d2e97f767719f 100644 --- a/src/test/ui/issues/issue-5997-struct.stderr +++ b/src/test/ui/issues/issue-5997-struct.stderr @@ -2,11 +2,11 @@ error[E0401]: can't use generic parameters from outer function --> $DIR/issue-5997-struct.rs:2:14 | LL | fn f() -> bool { - | - - type parameter from outer function - | | - | try adding a local generic parameter in this method instead + | - type parameter from outer function LL | struct S(T); - | ^ use of generic parameter from outer function + | -^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error: aborting due to previous error diff --git a/src/test/ui/nested-ty-params.stderr b/src/test/ui/nested-ty-params.stderr index f6741b5e5e82a..8f4746f5ec3bd 100644 --- a/src/test/ui/nested-ty-params.stderr +++ b/src/test/ui/nested-ty-params.stderr @@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function LL | fn hd(v: Vec ) -> U { | - type parameter from outer function LL | fn hd1(w: [U]) -> U { return w[0]; } - | --- ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `hd1` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error[E0401]: can't use generic parameters from outer function --> $DIR/nested-ty-params.rs:3:23 @@ -14,9 +14,9 @@ error[E0401]: can't use generic parameters from outer function LL | fn hd(v: Vec ) -> U { | - type parameter from outer function LL | fn hd1(w: [U]) -> U { return w[0]; } - | --- ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `hd1` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve/bad-type-env-capture.stderr b/src/test/ui/resolve/bad-type-env-capture.stderr index 6f24c0d86997e..b6282c2d0703b 100644 --- a/src/test/ui/resolve/bad-type-env-capture.stderr +++ b/src/test/ui/resolve/bad-type-env-capture.stderr @@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function LL | fn foo() { | - type parameter from outer function LL | fn bar(b: T) { } - | --- ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `bar` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error: aborting due to previous error diff --git a/src/test/ui/resolve/issue-3021-c.stderr b/src/test/ui/resolve/issue-3021-c.stderr index 8764ac8a8563c..5176efc3a6be7 100644 --- a/src/test/ui/resolve/issue-3021-c.stderr +++ b/src/test/ui/resolve/issue-3021-c.stderr @@ -3,22 +3,22 @@ error[E0401]: can't use generic parameters from outer function | LL | fn siphash() { | - type parameter from outer function -... +LL | +LL | trait U { + | - help: try using a local generic parameter instead: `` LL | fn g(&self, x: T) -> T; - | - ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `g` + | ^ use of generic parameter from outer function error[E0401]: can't use generic parameters from outer function --> $DIR/issue-3021-c.rs:4:30 | LL | fn siphash() { | - type parameter from outer function -... +LL | +LL | trait U { + | - help: try using a local generic parameter instead: `` LL | fn g(&self, x: T) -> T; - | - ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `g` + | ^ use of generic parameter from outer function error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr b/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr index 10a703ee09351..0a6d1cc3bcd45 100644 --- a/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr +++ b/src/test/ui/resolve/resolve-type-param-in-item-in-trait.stderr @@ -4,8 +4,8 @@ error[E0401]: can't use generic parameters from outer function LL | trait TraitA { | - type parameter from outer function LL | fn outer(&self) { - | ----- try adding a local generic parameter in this method instead LL | enum Foo { + | - help: try using a local generic parameter instead: `A,` LL | Variance(A) | ^ use of generic parameter from outer function @@ -15,9 +15,10 @@ error[E0401]: can't use generic parameters from outer function LL | trait TraitB { | - type parameter from outer function LL | fn outer(&self) { - | ----- try adding a local generic parameter in this method instead LL | struct Foo(A); - | ^ use of generic parameter from outer function + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `A,` error[E0401]: can't use generic parameters from outer function --> $DIR/resolve-type-param-in-item-in-trait.rs:23:28 @@ -25,9 +26,10 @@ error[E0401]: can't use generic parameters from outer function LL | trait TraitC { | - type parameter from outer function LL | fn outer(&self) { - | ----- try adding a local generic parameter in this method instead LL | struct Foo { a: A } - | ^ use of generic parameter from outer function + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `A,` error[E0401]: can't use generic parameters from outer function --> $DIR/resolve-type-param-in-item-in-trait.rs:30:22 @@ -36,9 +38,9 @@ LL | trait TraitD { | - type parameter from outer function LL | fn outer(&self) { LL | fn foo(a: A) { } - | ------ ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `foo` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `A,` error: aborting due to 4 previous errors diff --git a/src/test/ui/type/type-arg-out-of-scope.stderr b/src/test/ui/type/type-arg-out-of-scope.stderr index 0b6283fbc51e9..7f18b4510f4b2 100644 --- a/src/test/ui/type/type-arg-out-of-scope.stderr +++ b/src/test/ui/type/type-arg-out-of-scope.stderr @@ -4,9 +4,9 @@ error[E0401]: can't use generic parameters from outer function LL | fn foo(x: T) { | - type parameter from outer function LL | fn bar(f: Box T>) { } - | --- ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `bar` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error[E0401]: can't use generic parameters from outer function --> $DIR/type-arg-out-of-scope.rs:3:35 @@ -14,9 +14,9 @@ error[E0401]: can't use generic parameters from outer function LL | fn foo(x: T) { | - type parameter from outer function LL | fn bar(f: Box T>) { } - | --- ^ use of generic parameter from outer function - | | - | help: try using a local generic parameter instead: `bar` + | - ^ use of generic parameter from outer function + | | + | help: try using a local generic parameter instead: `` error: aborting due to 2 previous errors From 362e6361d09f554b438f638fc8113b6091aa01b8 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 14 Jul 2022 17:27:49 +0200 Subject: [PATCH 09/13] Do not call generate_fn_name_span in typeck. --- .../rustc_typeck/src/check/compare_method.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_typeck/src/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs index dfef924f6993a..df171c2531a7a 100644 --- a/compiler/rustc_typeck/src/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -858,8 +858,7 @@ fn compare_synthetic_generics<'tcx>( { if impl_synthetic != trait_synthetic { let impl_def_id = impl_def_id.expect_local(); - let impl_hir_id = tcx.hir().local_def_id_to_hir_id(impl_def_id); - let impl_span = tcx.hir().span(impl_hir_id); + let impl_span = tcx.def_span(impl_def_id); let trait_span = tcx.def_span(trait_def_id); let mut err = struct_span_err!( tcx.sess, @@ -878,17 +877,16 @@ fn compare_synthetic_generics<'tcx>( // try taking the name from the trait impl // FIXME: this is obviously suboptimal since the name can already be used // as another generic argument - let new_name = tcx.sess.source_map().span_to_snippet(trait_span).ok()?; + let new_name = tcx.opt_item_name(trait_def_id)?; let trait_m = trait_m.def_id.as_local()?; - let trait_m = tcx.hir().trait_item(hir::TraitItemId { def_id: trait_m }); + let trait_m = tcx.hir().expect_trait_item(trait_m); let impl_m = impl_m.def_id.as_local()?; - let impl_m = tcx.hir().impl_item(hir::ImplItemId { def_id: impl_m }); + let impl_m = tcx.hir().expect_impl_item(impl_m); // in case there are no generics, take the spot between the function name // and the opening paren of the argument list - let new_generics_span = - tcx.sess.source_map().generate_fn_name_span(impl_span)?.shrink_to_hi(); + let new_generics_span = tcx.def_ident_span(impl_def_id)?.shrink_to_hi(); // in case there are generics, just replace them let generics_span = impl_m.generics.span.substitute_dummy(new_generics_span); @@ -900,7 +898,7 @@ fn compare_synthetic_generics<'tcx>( "try changing the `impl Trait` argument to a generic parameter", vec![ // replace `impl Trait` with `T` - (impl_span, new_name), + (impl_span, new_name.to_string()), // replace impl method generics with trait method generics // This isn't quite right, as users might have changed the names // of the generics, but it works for the common case @@ -917,7 +915,7 @@ fn compare_synthetic_generics<'tcx>( err.span_label(impl_span, "expected `impl Trait`, found generic parameter"); (|| { let impl_m = impl_m.def_id.as_local()?; - let impl_m = tcx.hir().impl_item(hir::ImplItemId { def_id: impl_m }); + let impl_m = tcx.hir().expect_impl_item(impl_m); let input_tys = match impl_m.kind { hir::ImplItemKind::Fn(ref sig, _) => sig.decl.inputs, _ => unreachable!(), From 6e88d738be05637824f581fc9cb59990406bf2ba Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 14 Jul 2022 17:28:34 +0200 Subject: [PATCH 10/13] Remove generate_fn_name_span and generate_local_type_param_snippet. --- compiler/rustc_span/src/source_map.rs | 87 --------------------------- 1 file changed, 87 deletions(-) diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs index 5f928707ea826..a32cabab4c407 100644 --- a/compiler/rustc_span/src/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -982,93 +982,6 @@ impl SourceMap { self.files().iter().fold(0, |a, f| a + f.count_lines()) } - pub fn generate_fn_name_span(&self, span: Span) -> Option { - let prev_span = self.span_extend_to_prev_str(span, "fn", true, true)?; - if let Ok(snippet) = self.span_to_snippet(prev_span) { - debug!( - "generate_fn_name_span: span={:?}, prev_span={:?}, snippet={:?}", - span, prev_span, snippet - ); - - if snippet.is_empty() { - return None; - }; - - let len = snippet - .find(|c: char| !c.is_alphanumeric() && c != '_') - .expect("no label after fn"); - Some(prev_span.with_hi(BytePos(prev_span.lo().0 + len as u32))) - } else { - None - } - } - - /// Takes the span of a type parameter in a function signature and try to generate a span for - /// the function name (with generics) and a new snippet for this span with the pointed type - /// parameter as a new local type parameter. - /// - /// For instance: - /// ```rust,ignore (pseudo-Rust) - /// // Given span - /// fn my_function(param: T) - /// // ^ Original span - /// - /// // Result - /// fn my_function(param: T) - /// // ^^^^^^^^^^^ Generated span with snippet `my_function` - /// ``` - /// - /// Attention: The method used is very fragile since it essentially duplicates the work of the - /// parser. If you need to use this function or something similar, please consider updating the - /// `SourceMap` functions and this function to something more robust. - pub fn generate_local_type_param_snippet(&self, span: Span) -> Option<(Span, String)> { - // Try to extend the span to the previous "fn" keyword to retrieve the function - // signature. - if let Some(sugg_span) = self.span_extend_to_prev_str(span, "fn", false, true) { - if let Ok(snippet) = self.span_to_snippet(sugg_span) { - // Consume the function name. - let mut offset = snippet - .find(|c: char| !c.is_alphanumeric() && c != '_') - .expect("no label after fn"); - - // Consume the generics part of the function signature. - let mut bracket_counter = 0; - let mut last_char = None; - for c in snippet[offset..].chars() { - match c { - '<' => bracket_counter += 1, - '>' => bracket_counter -= 1, - '(' => { - if bracket_counter == 0 { - break; - } - } - _ => {} - } - offset += c.len_utf8(); - last_char = Some(c); - } - - // Adjust the suggestion span to encompass the function name with its generics. - let sugg_span = sugg_span.with_hi(BytePos(sugg_span.lo().0 + offset as u32)); - - // Prepare the new suggested snippet to append the type parameter that triggered - // the error in the generics of the function signature. - let mut new_snippet = if last_char == Some('>') { - format!("{}, ", &snippet[..(offset - '>'.len_utf8())]) - } else { - format!("{}<", &snippet[..offset]) - }; - new_snippet - .push_str(&self.span_to_snippet(span).unwrap_or_else(|_| "T".to_string())); - new_snippet.push('>'); - - return Some((sugg_span, new_snippet)); - } - } - - None - } pub fn ensure_source_file_source_present(&self, source_file: Lrc) -> bool { source_file.add_external_src(|| { match source_file.name { From da9ccc2c98ac4d88e5f2b940b9b61ec6d25facaa Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Thu, 14 Jul 2022 17:40:43 +0200 Subject: [PATCH 11/13] Remove FnItemRibKind. --- compiler/rustc_resolve/src/ident.rs | 12 +----------- compiler/rustc_resolve/src/late.rs | 25 +++++++++---------------- 2 files changed, 10 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 0d8f1cf365643..41a0c76d83a95 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1105,7 +1105,7 @@ impl<'a> Resolver<'a> { | ForwardGenericParamBanRibKind => { // Nothing to do. Continue. } - ItemRibKind(_) | FnItemRibKind | AssocItemRibKind => { + ItemRibKind(_) | AssocItemRibKind => { // This was an attempt to access an upvar inside a // named function item. This is not allowed, so we // report an error. @@ -1173,7 +1173,6 @@ impl<'a> Resolver<'a> { | ModuleRibKind(..) | MacroDefinition(..) | InlineAsmSymRibKind - | FnItemRibKind | AssocItemRibKind | ForwardGenericParamBanRibKind => { // Nothing to do. Continue. @@ -1236,14 +1235,6 @@ impl<'a> Resolver<'a> { } } Res::Def(DefKind::ConstParam, _) => { - let mut ribs = ribs.iter().peekable(); - if let Some(Rib { kind: FnItemRibKind, .. }) = ribs.peek() { - // When declaring const parameters inside function signatures, the first rib - // is always a `FnItemRibKind`. In this case, we can skip it, to avoid it - // (spuriously) conflicting with the const param. - ribs.next(); - } - for rib in ribs { let has_generic_params = match rib.kind { NormalRibKind @@ -1251,7 +1242,6 @@ impl<'a> Resolver<'a> { | ModuleRibKind(..) | MacroDefinition(..) | InlineAsmSymRibKind - | FnItemRibKind | AssocItemRibKind | ForwardGenericParamBanRibKind => continue, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 748a0781c4f7a..693ec86616ee4 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -132,10 +132,6 @@ pub(crate) enum RibKind<'a> { /// We passed through a closure. Disallow labels. ClosureOrAsyncRibKind, - /// We passed through a function definition. Disallow upvars. - /// Permit only those const parameters that are specified in the function's generics. - FnItemRibKind, - /// We passed through an item scope. Disallow upvars. ItemRibKind(HasGenericParams), @@ -172,7 +168,6 @@ impl RibKind<'_> { match self { NormalRibKind | ClosureOrAsyncRibKind - | FnItemRibKind | ConstantItemRibKind(..) | ModuleRibKind(_) | MacroDefinition(_) @@ -189,7 +184,6 @@ impl RibKind<'_> { AssocItemRibKind | ClosureOrAsyncRibKind - | FnItemRibKind | ItemRibKind(..) | ConstantItemRibKind(..) | ModuleRibKind(..) @@ -793,7 +787,8 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } } fn visit_fn(&mut self, fn_kind: FnKind<'ast>, sp: Span, fn_id: NodeId) { - let rib_kind = match fn_kind { + let previous_value = self.diagnostic_metadata.current_function; + match fn_kind { // Bail if the function is foreign, and thus cannot validly have // a body, or if there's no body for some other reason. FnKind::Fn(FnCtxt::Foreign, _, sig, _, generics, _) @@ -816,20 +811,18 @@ impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { ); return; } - FnKind::Fn(FnCtxt::Free, ..) => FnItemRibKind, - FnKind::Fn(FnCtxt::Assoc(_), ..) => NormalRibKind, - FnKind::Closure(..) => ClosureOrAsyncRibKind, + FnKind::Fn(..) => { + self.diagnostic_metadata.current_function = Some((fn_kind, sp)); + } + // Do not update `current_function` for closures: it suggests `self` parameters. + FnKind::Closure(..) => {} }; - let previous_value = self.diagnostic_metadata.current_function; - if matches!(fn_kind, FnKind::Fn(..)) { - self.diagnostic_metadata.current_function = Some((fn_kind, sp)); - } debug!("(resolving function) entering function"); // Create a value rib for the function. - self.with_rib(ValueNS, rib_kind, |this| { + self.with_rib(ValueNS, ClosureOrAsyncRibKind, |this| { // Create a label rib for the function. - this.with_label_rib(FnItemRibKind, |this| { + this.with_label_rib(ClosureOrAsyncRibKind, |this| { match fn_kind { FnKind::Fn(_, _, sig, _, generics, body) => { this.visit_generics(generics); From dff428013dde1e89b6c644b9649f0dc53ceac354 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Tue, 23 Aug 2022 00:09:58 +0200 Subject: [PATCH 12/13] Mark suggestion as MaybeIncorrect. --- compiler/rustc_resolve/src/diagnostics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index fc19835019881..25013036d8749 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -566,7 +566,7 @@ impl<'a> Resolver<'a> { (span, snippet) }; // Suggest the modification to the user - err.span_suggestion(span, sugg_msg, snippet, Applicability::MachineApplicable); + err.span_suggestion(span, sugg_msg, snippet, Applicability::MaybeIncorrect); } err From 8e6c5ad69668cb603641fc8445a62f004dc06828 Mon Sep 17 00:00:00 2001 From: nils <48135649+Nilstrieb@users.noreply.github.com> Date: Tue, 23 Aug 2022 08:18:18 +0200 Subject: [PATCH 13/13] Fix typo in UnreachableProp --- compiler/rustc_mir_transform/src/unreachable_prop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_mir_transform/src/unreachable_prop.rs b/compiler/rustc_mir_transform/src/unreachable_prop.rs index 56d7799a125b0..95fda2eafe8a1 100644 --- a/compiler/rustc_mir_transform/src/unreachable_prop.rs +++ b/compiler/rustc_mir_transform/src/unreachable_prop.rs @@ -84,7 +84,7 @@ where TerminatorKind::Unreachable } else if is_unreachable(otherwise) { // If there are multiple targets, don't delete unreachable branches (like an unreachable otherwise) - // unless otherwise is unrachable, in which case deleting a normal branch causes it to be merged with + // unless otherwise is unreachable, in which case deleting a normal branch causes it to be merged with // the otherwise, keeping its unreachable. // This looses information about reachability causing worse codegen. // For example (see src/test/codegen/match-optimizes-away.rs)