diff options
Diffstat (limited to 'compiler')
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/eval_context.rs | 23 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/intern.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_const_eval/src/interpret/validity.rs | 7 | ||||
| -rw-r--r-- | compiler/rustc_driver_impl/src/lib.rs | 75 | ||||
| -rw-r--r-- | compiler/rustc_driver_impl/src/signal_handler.rs | 142 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/expr.rs | 10 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/method/mod.rs | 5 | ||||
| -rw-r--r-- | compiler/rustc_hir_typeck/src/method/suggest.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_middle/src/hir/map/mod.rs | 13 | ||||
| -rw-r--r-- | compiler/rustc_mir_transform/src/const_prop_lint.rs | 3 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/item.rs | 16 | ||||
| -rw-r--r-- | compiler/rustc_parse/src/parser/ty.rs | 38 | ||||
| -rw-r--r-- | compiler/rustc_trait_selection/src/solve/search_graph/mod.rs | 6 |
13 files changed, 232 insertions, 112 deletions
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 90848dbfbc7..bd3d87470c9 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -25,8 +25,8 @@ use super::{ Scalar, StackPopJump, }; use crate::errors::{self, ErroneousConstUsed}; -use crate::fluent_generated as fluent; use crate::util; +use crate::{fluent_generated as fluent, ReportErrorExt}; pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> { /// Stores the `Machine` instance. @@ -432,6 +432,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { .map_or(CRATE_HIR_ID, |def_id| self.tcx.hir().local_def_id_to_hir_id(def_id)) } + /// Turn the given error into a human-readable string. Expects the string to be printed, so if + /// `RUSTC_CTFE_BACKTRACE` is set this will show a backtrace of the rustc internals that + /// triggered the error. + /// + /// This is NOT the preferred way to render an error; use `report` from `const_eval` instead. + /// However, this is useful when error messages appear in ICEs. + pub fn format_error(&self, e: InterpErrorInfo<'tcx>) -> String { + let (e, backtrace) = e.into_parts(); + backtrace.print_backtrace(); + // FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the + // label and arguments from the InterpError. + let handler = &self.tcx.sess.parse_sess.span_diagnostic; + #[allow(rustc::untranslatable_diagnostic)] + let mut diag = self.tcx.sess.struct_allow(""); + let msg = e.diagnostic_message(); + e.add_args(handler, &mut diag); + let s = handler.eagerly_translate_to_string(msg, diag.args()); + diag.cancel(); + s + } + #[inline(always)] pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>] { M::stack(self) diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 910c3ca5d0a..42950d1ffb0 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -378,7 +378,8 @@ pub fn intern_const_alloc_recursive< ecx.tcx.sess.delay_span_bug( ecx.tcx.span, format!( - "error during interning should later cause validation failure: {error:?}" + "error during interning should later cause validation failure: {}", + ecx.format_error(error), ), ); } diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs index d3f05af1c72..0d08d6be919 100644 --- a/compiler/rustc_const_eval/src/interpret/validity.rs +++ b/compiler/rustc_const_eval/src/interpret/validity.rs @@ -911,9 +911,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // Complain about any other kind of error -- those are bad because we'd like to // report them in a way that shows *where* in the value the issue lies. Err(err) => { - let (err, backtrace) = err.into_parts(); - backtrace.print_backtrace(); - bug!("Unexpected Undefined Behavior error during validation: {err:?}"); + bug!( + "Unexpected Undefined Behavior error during validation: {}", + self.format_error(err) + ); } } } diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 47180eb1823..1a16759d7f9 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -85,6 +85,15 @@ pub mod pretty; #[macro_use] mod print; mod session_diagnostics; +#[cfg(all(unix, any(target_env = "gnu", target_os = "macos")))] +mod signal_handler; + +#[cfg(not(all(unix, any(target_env = "gnu", target_os = "macos"))))] +mod signal_handler { + /// On platforms which don't support our signal handler's requirements, + /// simply use the default signal handler provided by std. + pub(super) fn install() {} +} use crate::session_diagnostics::{ RLinkEmptyVersionNumber, RLinkEncodingVersionMismatch, RLinkRustcVersionMismatch, @@ -1440,72 +1449,6 @@ pub fn init_env_logger(handler: &EarlyErrorHandler, env: &str) { } } -#[cfg(all(unix, any(target_env = "gnu", target_os = "macos")))] -mod signal_handler { - extern "C" { - fn backtrace_symbols_fd( - buffer: *const *mut libc::c_void, - size: libc::c_int, - fd: libc::c_int, - ); - } - - extern "C" fn print_stack_trace(_: libc::c_int) { - const MAX_FRAMES: usize = 256; - static mut STACK_TRACE: [*mut libc::c_void; MAX_FRAMES] = - [std::ptr::null_mut(); MAX_FRAMES]; - unsafe { - let depth = libc::backtrace(STACK_TRACE.as_mut_ptr(), MAX_FRAMES as i32); - if depth == 0 { - return; - } - backtrace_symbols_fd(STACK_TRACE.as_ptr(), depth, 2); - } - } - - /// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the - /// process, print a stack trace and then exit. - pub(super) fn install() { - use std::alloc::{alloc, Layout}; - - unsafe { - let alt_stack_size: usize = min_sigstack_size() + 64 * 1024; - let mut alt_stack: libc::stack_t = std::mem::zeroed(); - alt_stack.ss_sp = alloc(Layout::from_size_align(alt_stack_size, 1).unwrap()).cast(); - alt_stack.ss_size = alt_stack_size; - libc::sigaltstack(&alt_stack, std::ptr::null_mut()); - - let mut sa: libc::sigaction = std::mem::zeroed(); - sa.sa_sigaction = print_stack_trace as libc::sighandler_t; - sa.sa_flags = libc::SA_NODEFER | libc::SA_RESETHAND | libc::SA_ONSTACK; - libc::sigemptyset(&mut sa.sa_mask); - libc::sigaction(libc::SIGSEGV, &sa, std::ptr::null_mut()); - } - } - - /// Modern kernels on modern hardware can have dynamic signal stack sizes. - #[cfg(any(target_os = "linux", target_os = "android"))] - fn min_sigstack_size() -> usize { - const AT_MINSIGSTKSZ: core::ffi::c_ulong = 51; - let dynamic_sigstksz = unsafe { libc::getauxval(AT_MINSIGSTKSZ) }; - // If getauxval couldn't find the entry, it returns 0, - // so take the higher of the "constant" and auxval. - // This transparently supports older kernels which don't provide AT_MINSIGSTKSZ - libc::MINSIGSTKSZ.max(dynamic_sigstksz as _) - } - - /// Not all OS support hardware where this is needed. - #[cfg(not(any(target_os = "linux", target_os = "android")))] - fn min_sigstack_size() -> usize { - libc::MINSIGSTKSZ - } -} - -#[cfg(not(all(unix, any(target_env = "gnu", target_os = "macos"))))] -mod signal_handler { - pub(super) fn install() {} -} - pub fn main() -> ! { let start_time = Instant::now(); let start_rss = get_resident_set_size(); diff --git a/compiler/rustc_driver_impl/src/signal_handler.rs b/compiler/rustc_driver_impl/src/signal_handler.rs new file mode 100644 index 00000000000..deca1082221 --- /dev/null +++ b/compiler/rustc_driver_impl/src/signal_handler.rs @@ -0,0 +1,142 @@ +//! Signal handler for rustc +//! Primarily used to extract a backtrace from stack overflow + +use std::alloc::{alloc, Layout}; +use std::{fmt, mem, ptr}; + +extern "C" { + fn backtrace_symbols_fd(buffer: *const *mut libc::c_void, size: libc::c_int, fd: libc::c_int); +} + +fn backtrace_stderr(buffer: &[*mut libc::c_void]) { + let size = buffer.len().try_into().unwrap_or_default(); + unsafe { backtrace_symbols_fd(buffer.as_ptr(), size, libc::STDERR_FILENO) }; +} + +/// Unbuffered, unsynchronized writer to stderr. +/// +/// Only acceptable because everything will end soon anyways. +struct RawStderr(()); + +impl fmt::Write for RawStderr { + fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> { + let ret = unsafe { libc::write(libc::STDERR_FILENO, s.as_ptr().cast(), s.len()) }; + if ret == -1 { Err(fmt::Error) } else { Ok(()) } + } +} + +/// We don't really care how many bytes we actually get out. SIGSEGV comes for our head. +/// Splash stderr with letters of our own blood to warn our friends about the monster. +macro raw_errln($tokens:tt) { + let _ = ::core::fmt::Write::write_fmt(&mut RawStderr(()), format_args!($tokens)); + let _ = ::core::fmt::Write::write_char(&mut RawStderr(()), '\n'); +} + +/// Signal handler installed for SIGSEGV +extern "C" fn print_stack_trace(_: libc::c_int) { + const MAX_FRAMES: usize = 256; + // Reserve data segment so we don't have to malloc in a signal handler, which might fail + // in incredibly undesirable and unexpected ways due to e.g. the allocator deadlocking + static mut STACK_TRACE: [*mut libc::c_void; MAX_FRAMES] = [ptr::null_mut(); MAX_FRAMES]; + let stack = unsafe { + // Collect return addresses + let depth = libc::backtrace(STACK_TRACE.as_mut_ptr(), MAX_FRAMES as i32); + if depth == 0 { + return; + } + &STACK_TRACE.as_slice()[0..(depth as _)] + }; + + // Just a stack trace is cryptic. Explain what we're doing. + raw_errln!("error: rustc interrupted by SIGSEGV, printing backtrace\n"); + let mut written = 1; + let mut consumed = 0; + // Begin elaborating return addrs into symbols and writing them directly to stderr + // Most backtraces are stack overflow, most stack overflows are from recursion + // Check for cycles before writing 250 lines of the same ~5 symbols + let cycled = |(runner, walker)| runner == walker; + let mut cyclic = false; + if let Some(period) = stack.iter().skip(1).step_by(2).zip(stack).position(cycled) { + let period = period.saturating_add(1); // avoid "what if wrapped?" branches + let Some(offset) = stack.iter().skip(period).zip(stack).position(cycled) else { + // impossible. + return; + }; + + // Count matching trace slices, else we could miscount "biphasic cycles" + // with the same period + loop entry but a different inner loop + let next_cycle = stack[offset..].chunks_exact(period).skip(1); + let cycles = 1 + next_cycle + .zip(stack[offset..].chunks_exact(period)) + .filter(|(next, prev)| next == prev) + .count(); + backtrace_stderr(&stack[..offset]); + written += offset; + consumed += offset; + if cycles > 1 { + raw_errln!("\n### cycle encountered after {offset} frames with period {period}"); + backtrace_stderr(&stack[consumed..consumed + period]); + raw_errln!("### recursed {cycles} times\n"); + written += period + 4; + consumed += period * cycles; + cyclic = true; + }; + } + let rem = &stack[consumed..]; + backtrace_stderr(rem); + raw_errln!(""); + written += rem.len() + 1; + + let random_depth = || 8 * 16; // chosen by random diceroll (2d20) + if cyclic || stack.len() > random_depth() { + // technically speculation, but assert it with confidence anyway. + // rustc only arrived in this signal handler because bad things happened + // and this message is for explaining it's not the programmer's fault + raw_errln!("note: rustc unexpectedly overflowed its stack! this is a bug"); + written += 1; + } + if stack.len() == MAX_FRAMES { + raw_errln!("note: maximum backtrace depth reached, frames may have been lost"); + written += 1; + } + raw_errln!("note: we would appreciate a report at https://github.com/rust-lang/rust"); + written += 1; + if written > 24 { + // We probably just scrolled the earlier "we got SIGSEGV" message off the terminal + raw_errln!("note: backtrace dumped due to SIGSEGV! resuming signal"); + }; +} + +/// When SIGSEGV is delivered to the process, print a stack trace and then exit. +pub(super) fn install() { + unsafe { + let alt_stack_size: usize = min_sigstack_size() + 64 * 1024; + let mut alt_stack: libc::stack_t = mem::zeroed(); + alt_stack.ss_sp = alloc(Layout::from_size_align(alt_stack_size, 1).unwrap()).cast(); + alt_stack.ss_size = alt_stack_size; + libc::sigaltstack(&alt_stack, ptr::null_mut()); + + let mut sa: libc::sigaction = mem::zeroed(); + sa.sa_sigaction = print_stack_trace as libc::sighandler_t; + sa.sa_flags = libc::SA_NODEFER | libc::SA_RESETHAND | libc::SA_ONSTACK; + libc::sigemptyset(&mut sa.sa_mask); + libc::sigaction(libc::SIGSEGV, &sa, ptr::null_mut()); + } +} + +/// Modern kernels on modern hardware can have dynamic signal stack sizes. +#[cfg(any(target_os = "linux", target_os = "android"))] +fn min_sigstack_size() -> usize { + const AT_MINSIGSTKSZ: core::ffi::c_ulong = 51; + let dynamic_sigstksz = unsafe { libc::getauxval(AT_MINSIGSTKSZ) }; + // If getauxval couldn't find the entry, it returns 0, + // so take the higher of the "constant" and auxval. + // This transparently supports older kernels which don't provide AT_MINSIGSTKSZ + libc::MINSIGSTKSZ.max(dynamic_sigstksz as _) +} + +/// Not all OS support hardware where this is needed. +#[cfg(not(any(target_os = "linux", target_os = "android")))] +fn min_sigstack_size() -> usize { + libc::MINSIGSTKSZ +} diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index 7cea40fdd64..a3b8c391e02 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2310,13 +2310,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let guar = if field.name == kw::Empty { self.tcx.sess.delay_span_bug(field.span, "field name with no name") - } else if self.method_exists( - field, - base_ty, - expr.hir_id, - true, - expected.only_has_type(self), - ) { + } else if self.method_exists(field, base_ty, expr.hir_id, expected.only_has_type(self)) { self.ban_take_value_of_method(expr, base_ty, field) } else if !base_ty.is_primitive_ty() { self.ban_nonexisting_field(field, base, expr, base_ty) @@ -2501,7 +2495,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut err = self.private_field_err(field, base_did); // Also check if an accessible method exists, which is often what is meant. - if self.method_exists(field, expr_t, expr.hir_id, false, return_ty) + if self.method_exists(field, expr_t, expr.hir_id, return_ty) && !self.expr_in_place(expr.hir_id) { self.suggest_method_call( diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs index 6dd131aa283..86a0e95de1d 100644 --- a/compiler/rustc_hir_typeck/src/method/mod.rs +++ b/compiler/rustc_hir_typeck/src/method/mod.rs @@ -89,14 +89,13 @@ pub enum CandidateSource { } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { - /// Determines whether the type `self_ty` supports a method name `method_name` or not. + /// Determines whether the type `self_ty` supports a visible method named `method_name` or not. #[instrument(level = "debug", skip(self))] pub fn method_exists( &self, method_name: Ident, self_ty: Ty<'tcx>, call_expr_id: hir::HirId, - allow_private: bool, return_type: Option<Ty<'tcx>>, ) -> bool { match self.probe_for_name( @@ -118,7 +117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } Err(NoMatch(..)) => false, Err(Ambiguity(..)) => true, - Err(PrivateMatch(..)) => allow_private, + Err(PrivateMatch(..)) => false, Err(IllegalSizedBound { .. }) => true, Err(BadReturnType) => false, } diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 72a04a02bf4..07c48ec6392 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2361,8 +2361,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Some(output_ty) => self.resolve_vars_if_possible(output_ty), _ => return, }; - let method_exists = - self.method_exists(item_name, output_ty, call.hir_id, true, return_type); + let method_exists = self.method_exists(item_name, output_ty, call.hir_id, return_type); debug!("suggest_await_before_method: is_method_exist={}", method_exists); if method_exists { err.span_suggestion_verbose( diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 467962b39bb..81de70c03d4 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -701,6 +701,8 @@ impl<'hir> Map<'hir> { // expressions. ignore_tail = true; } + + let mut prev_hir_id = None; while let Some((hir_id, node)) = iter.next() { if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) { match next_node { @@ -715,7 +717,14 @@ impl<'hir> Map<'hir> { | Node::ForeignItem(_) | Node::TraitItem(_) | Node::Expr(Expr { kind: ExprKind::Closure { .. }, .. }) - | Node::ImplItem(_) => return Some(hir_id), + | Node::ImplItem(_) + // The input node `id` must be enclosed in the method's body as opposed + // to some other place such as its return type (fixes #114918). + // We verify that indirectly by checking that the previous node is the + // current node's body + if node.body_id().map(|b| b.hir_id) == prev_hir_id => { + return Some(hir_id) + } // Ignore `return`s on the first iteration Node::Expr(Expr { kind: ExprKind::Loop(..) | ExprKind::Ret(..), .. }) | Node::Local(_) => { @@ -723,6 +732,8 @@ impl<'hir> Map<'hir> { } _ => {} } + + prev_hir_id = Some(hir_id); } None } diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index da8913d604b..755b3985791 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -273,7 +273,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // dedicated error variants should be introduced instead. assert!( !error.kind().formatted_string(), - "const-prop encountered formatting error: {error:?}", + "const-prop encountered formatting error: {}", + self.ecx.format_error(error), ); None } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index 5db31c23478..233c7016417 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -1851,21 +1851,11 @@ impl<'a> Parser<'a> { attrs: AttrVec, ) -> PResult<'a, FieldDef> { let name = self.parse_field_ident(adt_ty, lo)?; - // Parse the macro invocation and recover if self.token.kind == token::Not { if let Err(mut err) = self.unexpected::<FieldDef>() { - err.subdiagnostic(MacroExpandsToAdtField { adt_ty }).emit(); - self.bump(); - self.parse_delim_args()?; - return Ok(FieldDef { - span: DUMMY_SP, - ident: None, - vis, - id: DUMMY_NODE_ID, - ty: self.mk_ty(DUMMY_SP, TyKind::Err), - attrs, - is_placeholder: false, - }); + // Encounter the macro invocation + err.subdiagnostic(MacroExpandsToAdtField { adt_ty }); + return Err(err); } } self.expect_field_ty_separator()?; diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 661113666cd..a25b0f1f893 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -891,18 +891,32 @@ impl<'a> Parser<'a> { // that we do not use the try operator when parsing the type because // if it fails then we get a parser error which we don't want (we're trying // to recover from errors, not make more). - let path = if self.may_recover() - && matches!(ty.kind, TyKind::Ptr(..) | TyKind::Ref(..)) - && let TyKind::Path(_, path) = &ty.peel_refs().kind { - // Just get the indirection part of the type. - let span = ty.span.until(path.span); - - err.span_suggestion_verbose( - span, - "consider removing the indirection", - "", - Applicability::MaybeIncorrect, - ); + let path = if self.may_recover() { + let (span, message, sugg, path, applicability) = match &ty.kind { + TyKind::Ptr(..) | TyKind::Ref(..) if let TyKind::Path(_, path) = &ty.peel_refs().kind => { + ( + ty.span.until(path.span), + "consider removing the indirection", + "", + path, + Applicability::MaybeIncorrect + ) + } + TyKind::ImplTrait(_, bounds) + if let [GenericBound::Trait(tr, ..), ..] = bounds.as_slice() => + { + ( + ty.span.until(tr.span), + "use the trait bounds directly", + "", + &tr.trait_ref.path, + Applicability::MachineApplicable + ) + } + _ => return Err(err) + }; + + err.span_suggestion_verbose(span, message, sugg, applicability); path.clone() } else { diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs index 49ebfa4e6cb..ca3c64b428e 100644 --- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs @@ -51,9 +51,13 @@ pub(super) struct SearchGraph<'tcx> { impl<'tcx> SearchGraph<'tcx> { pub(super) fn new(tcx: TyCtxt<'tcx>, mode: SolverMode) -> SearchGraph<'tcx> { + let local_overflow_limit = { + let recursion_limit = tcx.recursion_limit().0; + if recursion_limit == 0 { 0 } else { recursion_limit.ilog2() as usize } + }; Self { mode, - local_overflow_limit: tcx.recursion_limit().0.ilog2() as usize, + local_overflow_limit, stack: Default::default(), provisional_cache: ProvisionalCache::empty(), } |
