Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 7659abc

Browse files
committedAug 30, 2023
Auto merge of #115370 - matthiaskrgr:rollup-l0e1zuj, r=matthiaskrgr
Rollup of 7 pull requests Successful merges: - #113565 (Make SIGSEGV handler emit nicer backtraces) - #114704 (parser: not insert dummy field in struct) - #115272 (miri/diagnostics: don't forget to print_backtrace when ICEing on unexpected errors) - #115313 (Make `get_return_block()` return `Some` only for HIR nodes in body) - #115347 (suggest removing `impl` in generic trait bound position) - #115355 (new solver: handle edge case of a recursion limit of 0) - #115363 (Don't suggest adding parentheses to call an inaccessible method.) r? `@ghost` `@rustbot` modify labels: rollup
2 parents 82c2eb4 + ea23478 commit 7659abc

File tree

30 files changed

+498
-188
lines changed

30 files changed

+498
-188
lines changed
 

‎compiler/rustc_const_eval/src/interpret/eval_context.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ use super::{
2525
Scalar, StackPopJump,
2626
};
2727
use crate::errors::{self, ErroneousConstUsed};
28-
use crate::fluent_generated as fluent;
2928
use crate::util;
29+
use crate::{fluent_generated as fluent, ReportErrorExt};
3030

3131
pub struct InterpCx<'mir, 'tcx, M: Machine<'mir, 'tcx>> {
3232
/// Stores the `Machine` instance.
@@ -432,6 +432,27 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
432432
.map_or(CRATE_HIR_ID, |def_id| self.tcx.hir().local_def_id_to_hir_id(def_id))
433433
}
434434

435+
/// Turn the given error into a human-readable string. Expects the string to be printed, so if
436+
/// `RUSTC_CTFE_BACKTRACE` is set this will show a backtrace of the rustc internals that
437+
/// triggered the error.
438+
///
439+
/// This is NOT the preferred way to render an error; use `report` from `const_eval` instead.
440+
/// However, this is useful when error messages appear in ICEs.
441+
pub fn format_error(&self, e: InterpErrorInfo<'tcx>) -> String {
442+
let (e, backtrace) = e.into_parts();
443+
backtrace.print_backtrace();
444+
// FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the
445+
// label and arguments from the InterpError.
446+
let handler = &self.tcx.sess.parse_sess.span_diagnostic;
447+
#[allow(rustc::untranslatable_diagnostic)]
448+
let mut diag = self.tcx.sess.struct_allow("");
449+
let msg = e.diagnostic_message();
450+
e.add_args(handler, &mut diag);
451+
let s = handler.eagerly_translate_to_string(msg, diag.args());
452+
diag.cancel();
453+
s
454+
}
455+
435456
#[inline(always)]
436457
pub(crate) fn stack(&self) -> &[Frame<'mir, 'tcx, M::Provenance, M::FrameExtra>] {
437458
M::stack(self)

‎compiler/rustc_const_eval/src/interpret/intern.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,8 @@ pub fn intern_const_alloc_recursive<
378378
ecx.tcx.sess.delay_span_bug(
379379
ecx.tcx.span,
380380
format!(
381-
"error during interning should later cause validation failure: {error:?}"
381+
"error during interning should later cause validation failure: {}",
382+
ecx.format_error(error),
382383
),
383384
);
384385
}

‎compiler/rustc_const_eval/src/interpret/validity.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -911,9 +911,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
911911
// Complain about any other kind of error -- those are bad because we'd like to
912912
// report them in a way that shows *where* in the value the issue lies.
913913
Err(err) => {
914-
let (err, backtrace) = err.into_parts();
915-
backtrace.print_backtrace();
916-
bug!("Unexpected Undefined Behavior error during validation: {err:?}");
914+
bug!(
915+
"Unexpected Undefined Behavior error during validation: {}",
916+
self.format_error(err)
917+
);
917918
}
918919
}
919920
}

‎compiler/rustc_driver_impl/src/lib.rs

Lines changed: 9 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@ pub mod pretty;
8585
#[macro_use]
8686
mod print;
8787
mod session_diagnostics;
88+
#[cfg(all(unix, any(target_env = "gnu", target_os = "macos")))]
89+
mod signal_handler;
90+
91+
#[cfg(not(all(unix, any(target_env = "gnu", target_os = "macos"))))]
92+
mod signal_handler {
93+
/// On platforms which don't support our signal handler's requirements,
94+
/// simply use the default signal handler provided by std.
95+
pub(super) fn install() {}
96+
}
8897

8998
use crate::session_diagnostics::{
9099
RLinkEmptyVersionNumber, RLinkEncodingVersionMismatch, RLinkRustcVersionMismatch,
@@ -1440,72 +1449,6 @@ pub fn init_env_logger(handler: &EarlyErrorHandler, env: &str) {
14401449
}
14411450
}
14421451

1443-
#[cfg(all(unix, any(target_env = "gnu", target_os = "macos")))]
1444-
mod signal_handler {
1445-
extern "C" {
1446-
fn backtrace_symbols_fd(
1447-
buffer: *const *mut libc::c_void,
1448-
size: libc::c_int,
1449-
fd: libc::c_int,
1450-
);
1451-
}
1452-
1453-
extern "C" fn print_stack_trace(_: libc::c_int) {
1454-
const MAX_FRAMES: usize = 256;
1455-
static mut STACK_TRACE: [*mut libc::c_void; MAX_FRAMES] =
1456-
[std::ptr::null_mut(); MAX_FRAMES];
1457-
unsafe {
1458-
let depth = libc::backtrace(STACK_TRACE.as_mut_ptr(), MAX_FRAMES as i32);
1459-
if depth == 0 {
1460-
return;
1461-
}
1462-
backtrace_symbols_fd(STACK_TRACE.as_ptr(), depth, 2);
1463-
}
1464-
}
1465-
1466-
/// When an error signal (such as SIGABRT or SIGSEGV) is delivered to the
1467-
/// process, print a stack trace and then exit.
1468-
pub(super) fn install() {
1469-
use std::alloc::{alloc, Layout};
1470-
1471-
unsafe {
1472-
let alt_stack_size: usize = min_sigstack_size() + 64 * 1024;
1473-
let mut alt_stack: libc::stack_t = std::mem::zeroed();
1474-
alt_stack.ss_sp = alloc(Layout::from_size_align(alt_stack_size, 1).unwrap()).cast();
1475-
alt_stack.ss_size = alt_stack_size;
1476-
libc::sigaltstack(&alt_stack, std::ptr::null_mut());
1477-
1478-
let mut sa: libc::sigaction = std::mem::zeroed();
1479-
sa.sa_sigaction = print_stack_trace as libc::sighandler_t;
1480-
sa.sa_flags = libc::SA_NODEFER | libc::SA_RESETHAND | libc::SA_ONSTACK;
1481-
libc::sigemptyset(&mut sa.sa_mask);
1482-
libc::sigaction(libc::SIGSEGV, &sa, std::ptr::null_mut());
1483-
}
1484-
}
1485-
1486-
/// Modern kernels on modern hardware can have dynamic signal stack sizes.
1487-
#[cfg(any(target_os = "linux", target_os = "android"))]
1488-
fn min_sigstack_size() -> usize {
1489-
const AT_MINSIGSTKSZ: core::ffi::c_ulong = 51;
1490-
let dynamic_sigstksz = unsafe { libc::getauxval(AT_MINSIGSTKSZ) };
1491-
// If getauxval couldn't find the entry, it returns 0,
1492-
// so take the higher of the "constant" and auxval.
1493-
// This transparently supports older kernels which don't provide AT_MINSIGSTKSZ
1494-
libc::MINSIGSTKSZ.max(dynamic_sigstksz as _)
1495-
}
1496-
1497-
/// Not all OS support hardware where this is needed.
1498-
#[cfg(not(any(target_os = "linux", target_os = "android")))]
1499-
fn min_sigstack_size() -> usize {
1500-
libc::MINSIGSTKSZ
1501-
}
1502-
}
1503-
1504-
#[cfg(not(all(unix, any(target_env = "gnu", target_os = "macos"))))]
1505-
mod signal_handler {
1506-
pub(super) fn install() {}
1507-
}
1508-
15091452
pub fn main() -> ! {
15101453
let start_time = Instant::now();
15111454
let start_rss = get_resident_set_size();
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
//! Signal handler for rustc
2+
//! Primarily used to extract a backtrace from stack overflow
3+
4+
use std::alloc::{alloc, Layout};
5+
use std::{fmt, mem, ptr};
6+
7+
extern "C" {
8+
fn backtrace_symbols_fd(buffer: *const *mut libc::c_void, size: libc::c_int, fd: libc::c_int);
9+
}
10+
11+
fn backtrace_stderr(buffer: &[*mut libc::c_void]) {
12+
let size = buffer.len().try_into().unwrap_or_default();
13+
unsafe { backtrace_symbols_fd(buffer.as_ptr(), size, libc::STDERR_FILENO) };
14+
}
15+
16+
/// Unbuffered, unsynchronized writer to stderr.
17+
///
18+
/// Only acceptable because everything will end soon anyways.
19+
struct RawStderr(());
20+
21+
impl fmt::Write for RawStderr {
22+
fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
23+
let ret = unsafe { libc::write(libc::STDERR_FILENO, s.as_ptr().cast(), s.len()) };
24+
if ret == -1 { Err(fmt::Error) } else { Ok(()) }
25+
}
26+
}
27+
28+
/// We don't really care how many bytes we actually get out. SIGSEGV comes for our head.
29+
/// Splash stderr with letters of our own blood to warn our friends about the monster.
30+
macro raw_errln($tokens:tt) {
31+
let _ = ::core::fmt::Write::write_fmt(&mut RawStderr(()), format_args!($tokens));
32+
let _ = ::core::fmt::Write::write_char(&mut RawStderr(()), '\n');
33+
}
34+
35+
/// Signal handler installed for SIGSEGV
36+
extern "C" fn print_stack_trace(_: libc::c_int) {
37+
const MAX_FRAMES: usize = 256;
38+
// Reserve data segment so we don't have to malloc in a signal handler, which might fail
39+
// in incredibly undesirable and unexpected ways due to e.g. the allocator deadlocking
40+
static mut STACK_TRACE: [*mut libc::c_void; MAX_FRAMES] = [ptr::null_mut(); MAX_FRAMES];
41+
let stack = unsafe {
42+
// Collect return addresses
43+
let depth = libc::backtrace(STACK_TRACE.as_mut_ptr(), MAX_FRAMES as i32);
44+
if depth == 0 {
45+
return;
46+
}
47+
&STACK_TRACE.as_slice()[0..(depth as _)]
48+
};
49+
50+
// Just a stack trace is cryptic. Explain what we're doing.
51+
raw_errln!("error: rustc interrupted by SIGSEGV, printing backtrace\n");
52+
let mut written = 1;
53+
let mut consumed = 0;
54+
// Begin elaborating return addrs into symbols and writing them directly to stderr
55+
// Most backtraces are stack overflow, most stack overflows are from recursion
56+
// Check for cycles before writing 250 lines of the same ~5 symbols
57+
let cycled = |(runner, walker)| runner == walker;
58+
let mut cyclic = false;
59+
if let Some(period) = stack.iter().skip(1).step_by(2).zip(stack).position(cycled) {
60+
let period = period.saturating_add(1); // avoid "what if wrapped?" branches
61+
let Some(offset) = stack.iter().skip(period).zip(stack).position(cycled) else {
62+
// impossible.
63+
return;
64+
};
65+
66+
// Count matching trace slices, else we could miscount "biphasic cycles"
67+
// with the same period + loop entry but a different inner loop
68+
let next_cycle = stack[offset..].chunks_exact(period).skip(1);
69+
let cycles = 1 + next_cycle
70+
.zip(stack[offset..].chunks_exact(period))
71+
.filter(|(next, prev)| next == prev)
72+
.count();
73+
backtrace_stderr(&stack[..offset]);
74+
written += offset;
75+
consumed += offset;
76+
if cycles > 1 {
77+
raw_errln!("\n### cycle encountered after {offset} frames with period {period}");
78+
backtrace_stderr(&stack[consumed..consumed + period]);
79+
raw_errln!("### recursed {cycles} times\n");
80+
written += period + 4;
81+
consumed += period * cycles;
82+
cyclic = true;
83+
};
84+
}
85+
let rem = &stack[consumed..];
86+
backtrace_stderr(rem);
87+
raw_errln!("");
88+
written += rem.len() + 1;
89+
90+
let random_depth = || 8 * 16; // chosen by random diceroll (2d20)
91+
if cyclic || stack.len() > random_depth() {
92+
// technically speculation, but assert it with confidence anyway.
93+
// rustc only arrived in this signal handler because bad things happened
94+
// and this message is for explaining it's not the programmer's fault
95+
raw_errln!("note: rustc unexpectedly overflowed its stack! this is a bug");
96+
written += 1;
97+
}
98+
if stack.len() == MAX_FRAMES {
99+
raw_errln!("note: maximum backtrace depth reached, frames may have been lost");
100+
written += 1;
101+
}
102+
raw_errln!("note: we would appreciate a report at https://github.com/rust-lang/rust");
103+
written += 1;
104+
if written > 24 {
105+
// We probably just scrolled the earlier "we got SIGSEGV" message off the terminal
106+
raw_errln!("note: backtrace dumped due to SIGSEGV! resuming signal");
107+
};
108+
}
109+
110+
/// When SIGSEGV is delivered to the process, print a stack trace and then exit.
111+
pub(super) fn install() {
112+
unsafe {
113+
let alt_stack_size: usize = min_sigstack_size() + 64 * 1024;
114+
let mut alt_stack: libc::stack_t = mem::zeroed();
115+
alt_stack.ss_sp = alloc(Layout::from_size_align(alt_stack_size, 1).unwrap()).cast();
116+
alt_stack.ss_size = alt_stack_size;
117+
libc::sigaltstack(&alt_stack, ptr::null_mut());
118+
119+
let mut sa: libc::sigaction = mem::zeroed();
120+
sa.sa_sigaction = print_stack_trace as libc::sighandler_t;
121+
sa.sa_flags = libc::SA_NODEFER | libc::SA_RESETHAND | libc::SA_ONSTACK;
122+
libc::sigemptyset(&mut sa.sa_mask);
123+
libc::sigaction(libc::SIGSEGV, &sa, ptr::null_mut());
124+
}
125+
}
126+
127+
/// Modern kernels on modern hardware can have dynamic signal stack sizes.
128+
#[cfg(any(target_os = "linux", target_os = "android"))]
129+
fn min_sigstack_size() -> usize {
130+
const AT_MINSIGSTKSZ: core::ffi::c_ulong = 51;
131+
let dynamic_sigstksz = unsafe { libc::getauxval(AT_MINSIGSTKSZ) };
132+
// If getauxval couldn't find the entry, it returns 0,
133+
// so take the higher of the "constant" and auxval.
134+
// This transparently supports older kernels which don't provide AT_MINSIGSTKSZ
135+
libc::MINSIGSTKSZ.max(dynamic_sigstksz as _)
136+
}
137+
138+
/// Not all OS support hardware where this is needed.
139+
#[cfg(not(any(target_os = "linux", target_os = "android")))]
140+
fn min_sigstack_size() -> usize {
141+
libc::MINSIGSTKSZ
142+
}

‎compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2310,13 +2310,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23102310

23112311
let guar = if field.name == kw::Empty {
23122312
self.tcx.sess.delay_span_bug(field.span, "field name with no name")
2313-
} else if self.method_exists(
2314-
field,
2315-
base_ty,
2316-
expr.hir_id,
2317-
true,
2318-
expected.only_has_type(self),
2319-
) {
2313+
} else if self.method_exists(field, base_ty, expr.hir_id, expected.only_has_type(self)) {
23202314
self.ban_take_value_of_method(expr, base_ty, field)
23212315
} else if !base_ty.is_primitive_ty() {
23222316
self.ban_nonexisting_field(field, base, expr, base_ty)
@@ -2501,7 +2495,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
25012495
let mut err = self.private_field_err(field, base_did);
25022496

25032497
// Also check if an accessible method exists, which is often what is meant.
2504-
if self.method_exists(field, expr_t, expr.hir_id, false, return_ty)
2498+
if self.method_exists(field, expr_t, expr.hir_id, return_ty)
25052499
&& !self.expr_in_place(expr.hir_id)
25062500
{
25072501
self.suggest_method_call(

‎compiler/rustc_hir_typeck/src/method/mod.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,14 +89,13 @@ pub enum CandidateSource {
8989
}
9090

9191
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
92-
/// Determines whether the type `self_ty` supports a method name `method_name` or not.
92+
/// Determines whether the type `self_ty` supports a visible method named `method_name` or not.
9393
#[instrument(level = "debug", skip(self))]
9494
pub fn method_exists(
9595
&self,
9696
method_name: Ident,
9797
self_ty: Ty<'tcx>,
9898
call_expr_id: hir::HirId,
99-
allow_private: bool,
10099
return_type: Option<Ty<'tcx>>,
101100
) -> bool {
102101
match self.probe_for_name(
@@ -118,7 +117,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
118117
}
119118
Err(NoMatch(..)) => false,
120119
Err(Ambiguity(..)) => true,
121-
Err(PrivateMatch(..)) => allow_private,
120+
Err(PrivateMatch(..)) => false,
122121
Err(IllegalSizedBound { .. }) => true,
123122
Err(BadReturnType) => false,
124123
}

‎compiler/rustc_hir_typeck/src/method/suggest.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2361,8 +2361,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
23612361
Some(output_ty) => self.resolve_vars_if_possible(output_ty),
23622362
_ => return,
23632363
};
2364-
let method_exists =
2365-
self.method_exists(item_name, output_ty, call.hir_id, true, return_type);
2364+
let method_exists = self.method_exists(item_name, output_ty, call.hir_id, return_type);
23662365
debug!("suggest_await_before_method: is_method_exist={}", method_exists);
23672366
if method_exists {
23682367
err.span_suggestion_verbose(

‎compiler/rustc_middle/src/hir/map/mod.rs

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -701,6 +701,8 @@ impl<'hir> Map<'hir> {
701701
// expressions.
702702
ignore_tail = true;
703703
}
704+
705+
let mut prev_hir_id = None;
704706
while let Some((hir_id, node)) = iter.next() {
705707
if let (Some((_, next_node)), false) = (iter.peek(), ignore_tail) {
706708
match next_node {
@@ -715,14 +717,23 @@ impl<'hir> Map<'hir> {
715717
| Node::ForeignItem(_)
716718
| Node::TraitItem(_)
717719
| Node::Expr(Expr { kind: ExprKind::Closure { .. }, .. })
718-
| Node::ImplItem(_) => return Some(hir_id),
720+
| Node::ImplItem(_)
721+
// The input node `id` must be enclosed in the method's body as opposed
722+
// to some other place such as its return type (fixes #114918).
723+
// We verify that indirectly by checking that the previous node is the
724+
// current node's body
725+
if node.body_id().map(|b| b.hir_id) == prev_hir_id => {
726+
return Some(hir_id)
727+
}
719728
// Ignore `return`s on the first iteration
720729
Node::Expr(Expr { kind: ExprKind::Loop(..) | ExprKind::Ret(..), .. })
721730
| Node::Local(_) => {
722731
return None;
723732
}
724733
_ => {}
725734
}
735+
736+
prev_hir_id = Some(hir_id);
726737
}
727738
None
728739
}

‎compiler/rustc_mir_transform/src/const_prop_lint.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,8 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
273273
// dedicated error variants should be introduced instead.
274274
assert!(
275275
!error.kind().formatted_string(),
276-
"const-prop encountered formatting error: {error:?}",
276+
"const-prop encountered formatting error: {}",
277+
self.ecx.format_error(error),
277278
);
278279
None
279280
}

‎compiler/rustc_parse/src/parser/item.rs

Lines changed: 3 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1851,21 +1851,11 @@ impl<'a> Parser<'a> {
18511851
attrs: AttrVec,
18521852
) -> PResult<'a, FieldDef> {
18531853
let name = self.parse_field_ident(adt_ty, lo)?;
1854-
// Parse the macro invocation and recover
18551854
if self.token.kind == token::Not {
18561855
if let Err(mut err) = self.unexpected::<FieldDef>() {
1857-
err.subdiagnostic(MacroExpandsToAdtField { adt_ty }).emit();
1858-
self.bump();
1859-
self.parse_delim_args()?;
1860-
return Ok(FieldDef {
1861-
span: DUMMY_SP,
1862-
ident: None,
1863-
vis,
1864-
id: DUMMY_NODE_ID,
1865-
ty: self.mk_ty(DUMMY_SP, TyKind::Err),
1866-
attrs,
1867-
is_placeholder: false,
1868-
});
1856+
// Encounter the macro invocation
1857+
err.subdiagnostic(MacroExpandsToAdtField { adt_ty });
1858+
return Err(err);
18691859
}
18701860
}
18711861
self.expect_field_ty_separator()?;

‎compiler/rustc_parse/src/parser/ty.rs

Lines changed: 26 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -891,18 +891,32 @@ impl<'a> Parser<'a> {
891891
// that we do not use the try operator when parsing the type because
892892
// if it fails then we get a parser error which we don't want (we're trying
893893
// to recover from errors, not make more).
894-
let path = if self.may_recover()
895-
&& matches!(ty.kind, TyKind::Ptr(..) | TyKind::Ref(..))
896-
&& let TyKind::Path(_, path) = &ty.peel_refs().kind {
897-
// Just get the indirection part of the type.
898-
let span = ty.span.until(path.span);
899-
900-
err.span_suggestion_verbose(
901-
span,
902-
"consider removing the indirection",
903-
"",
904-
Applicability::MaybeIncorrect,
905-
);
894+
let path = if self.may_recover() {
895+
let (span, message, sugg, path, applicability) = match &ty.kind {
896+
TyKind::Ptr(..) | TyKind::Ref(..) if let TyKind::Path(_, path) = &ty.peel_refs().kind => {
897+
(
898+
ty.span.until(path.span),
899+
"consider removing the indirection",
900+
"",
901+
path,
902+
Applicability::MaybeIncorrect
903+
)
904+
}
905+
TyKind::ImplTrait(_, bounds)
906+
if let [GenericBound::Trait(tr, ..), ..] = bounds.as_slice() =>
907+
{
908+
(
909+
ty.span.until(tr.span),
910+
"use the trait bounds directly",
911+
"",
912+
&tr.trait_ref.path,
913+
Applicability::MachineApplicable
914+
)
915+
}
916+
_ => return Err(err)
917+
};
918+
919+
err.span_suggestion_verbose(span, message, sugg, applicability);
906920

907921
path.clone()
908922
} else {

‎compiler/rustc_trait_selection/src/solve/search_graph/mod.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,13 @@ pub(super) struct SearchGraph<'tcx> {
5151

5252
impl<'tcx> SearchGraph<'tcx> {
5353
pub(super) fn new(tcx: TyCtxt<'tcx>, mode: SolverMode) -> SearchGraph<'tcx> {
54+
let local_overflow_limit = {
55+
let recursion_limit = tcx.recursion_limit().0;
56+
if recursion_limit == 0 { 0 } else { recursion_limit.ilog2() as usize }
57+
};
5458
Self {
5559
mode,
56-
local_overflow_limit: tcx.recursion_limit().0.ilog2() as usize,
60+
local_overflow_limit,
5761
stack: Default::default(),
5862
provisional_cache: ProvisionalCache::empty(),
5963
}

‎src/tools/miri/src/diagnostics.rs

Lines changed: 27 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
use std::fmt;
1+
use std::fmt::{self, Write};
22
use std::num::NonZeroU64;
33

44
use log::trace;
55

6-
use rustc_const_eval::ReportErrorExt;
76
use rustc_errors::DiagnosticMessage;
87
use rustc_span::{source_map::DUMMY_SP, SpanData, Symbol};
98
use rustc_target::abi::{Align, Size};
@@ -271,10 +270,13 @@ pub fn report_error<'tcx, 'mir>(
271270
};
272271
(title, helps)
273272
} else {
274-
#[rustfmt::skip]
275273
let title = match e.kind() {
276-
UndefinedBehavior(UndefinedBehaviorInfo::ValidationError(e)) if matches!(e.kind, ValidationErrorKind::PointerAsInt { .. } | ValidationErrorKind::PartialPointer) =>
277-
bug!("This validation error should be impossible in Miri: {:?}", e.kind),
274+
UndefinedBehavior(UndefinedBehaviorInfo::ValidationError(validation_err))
275+
if matches!(validation_err.kind, ValidationErrorKind::PointerAsInt { .. } | ValidationErrorKind::PartialPointer) =>
276+
{
277+
ecx.handle_ice(); // print interpreter backtrace
278+
bug!("This validation error should be impossible in Miri: {}", ecx.format_error(e));
279+
}
278280
UndefinedBehavior(_) =>
279281
"Undefined Behavior",
280282
ResourceExhaustion(_) =>
@@ -290,8 +292,10 @@ pub fn report_error<'tcx, 'mir>(
290292
InvalidProgramInfo::Layout(..)
291293
) =>
292294
"post-monomorphization error",
293-
kind =>
294-
bug!("This error should be impossible in Miri: {kind:?}"),
295+
_ => {
296+
ecx.handle_ice(); // print interpreter backtrace
297+
bug!("This error should be impossible in Miri: {}", ecx.format_error(e));
298+
}
295299
};
296300
#[rustfmt::skip]
297301
let helps = match e.kind() {
@@ -333,30 +337,22 @@ pub fn report_error<'tcx, 'mir>(
333337

334338
let stacktrace = ecx.generate_stacktrace();
335339
let (stacktrace, was_pruned) = prune_stacktrace(stacktrace, &ecx.machine);
336-
let (e, backtrace) = e.into_parts();
337-
backtrace.print_backtrace();
338-
339-
// We want to dump the allocation if this is `InvalidUninitBytes`. Since `add_args` consumes
340-
// the `InterpError`, we extract the variables it before that.
341-
let extra = match e {
342-
UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) =>
343-
Some((alloc_id, access)),
344-
_ => None,
345-
};
346340

347-
// FIXME(fee1-dead), HACK: we want to use the error as title therefore we can just extract the
348-
// label and arguments from the InterpError.
349-
let e = {
350-
let handler = &ecx.tcx.sess.parse_sess.span_diagnostic;
351-
let mut diag = ecx.tcx.sess.struct_allow("");
352-
let msg = e.diagnostic_message();
353-
e.add_args(handler, &mut diag);
354-
let s = handler.eagerly_translate_to_string(msg, diag.args());
355-
diag.cancel();
356-
s
357-
};
341+
// We want to dump the allocation if this is `InvalidUninitBytes`. Since `format_error` consumes `e`, we compute the outut early.
342+
let mut extra = String::new();
343+
match e.kind() {
344+
UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => {
345+
writeln!(
346+
extra,
347+
"Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:",
348+
range = access.bad,
349+
).unwrap();
350+
writeln!(extra, "{:?}", ecx.dump_alloc(*alloc_id)).unwrap();
351+
}
352+
_ => {}
353+
}
358354

359-
msg.insert(0, e);
355+
msg.insert(0, ecx.format_error(e));
360356

361357
report_msg(
362358
DiagLevel::Error,
@@ -375,6 +371,8 @@ pub fn report_error<'tcx, 'mir>(
375371
);
376372
}
377373

374+
eprint!("{extra}"); // newlines are already in the string
375+
378376
// Debug-dump all locals.
379377
for (i, frame) in ecx.active_thread_stack().iter().enumerate() {
380378
trace!("-------------------");
@@ -385,15 +383,6 @@ pub fn report_error<'tcx, 'mir>(
385383
}
386384
}
387385

388-
// Extra output to help debug specific issues.
389-
if let Some((alloc_id, access)) = extra {
390-
eprintln!(
391-
"Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:",
392-
range = access.bad,
393-
);
394-
eprintln!("{:?}", ecx.dump_alloc(alloc_id));
395-
}
396-
397386
None
398387
}
399388

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
trait Tr {
2+
type Assoc: impl Sized;
3+
//~^ ERROR expected a trait, found type
4+
//~| HELP use the trait bounds directly
5+
6+
fn fn_with_generics<T>()
7+
where
8+
T: impl Sized
9+
//~^ ERROR expected a trait, found type
10+
//~| HELP use the trait bounds directly
11+
{}
12+
}
13+
14+
fn main() {}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
error: expected a trait, found type
2+
--> $DIR/suggest-removing-impl.rs:2:17
3+
|
4+
LL | type Assoc: impl Sized;
5+
| ^^^^^^^^^^
6+
|
7+
help: use the trait bounds directly
8+
|
9+
LL - type Assoc: impl Sized;
10+
LL + type Assoc: Sized;
11+
|
12+
13+
error: expected a trait, found type
14+
--> $DIR/suggest-removing-impl.rs:8:12
15+
|
16+
LL | T: impl Sized
17+
| ^^^^^^^^^^
18+
|
19+
help: use the trait bounds directly
20+
|
21+
LL - T: impl Sized
22+
LL + T: Sized
23+
|
24+
25+
error: aborting due to 2 previous errors
26+
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// This error is an E0609 and *not* an E0615 because the fact that the method exists is not
2+
// relevant.
3+
mod foo {
4+
pub struct Foo {
5+
x: u32,
6+
}
7+
8+
impl Foo {
9+
fn method(&self) {}
10+
}
11+
}
12+
13+
fn main() {
14+
let f = foo::Foo { x: 0 };
15+
f.method; //~ ERROR E0609
16+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0609]: no field `method` on type `Foo`
2+
--> $DIR/E0609-private-method.rs:15:7
3+
|
4+
LL | f.method;
5+
| ^^^^^^ unknown field
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0609`.

‎tests/ui/parser/macro/macro-expand-to-field.rs

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// compile-flags: --crate-type=lib
22

3+
// https://github.com/rust-lang/rust/issues/113766
4+
35
macro_rules! field {
46
($name:ident:$type:ty) => {
57
$name:$type
@@ -13,15 +15,14 @@ macro_rules! variant {
1315
}
1416

1517
struct Struct {
18+
//~^ NOTE while parsing this struct
1619
field!(bar:u128),
1720
//~^ NOTE macros cannot expand to struct fields
1821
//~| ERROR unexpected token: `!`
1922
//~| NOTE unexpected token after this
2023
a: u32,
2124
b: u32,
22-
field!(recovers:()), //~ NOTE macros cannot expand to struct fields
23-
//~^ ERROR unexpected token: `!`
24-
//~^^ NOTE unexpected token after this
25+
field!(recovers:()),
2526
}
2627

2728
enum EnumVariant {
@@ -35,7 +36,7 @@ enum EnumVariant {
3536
//~^ NOTE macros cannot expand to enum variants
3637
//~| ERROR unexpected token: `!`
3738
//~| NOTE unexpected token after this
38-
Data {
39+
Data { //~ NOTE while parsing this struct
3940
field!(x:u32),
4041
//~^ NOTE macros cannot expand to struct fields
4142
//~| ERROR unexpected token: `!`
@@ -44,27 +45,35 @@ enum EnumVariant {
4445
}
4546

4647
enum EnumVariantField {
47-
Named {
48+
Named { //~ NOTE while parsing this struct
4849
field!(oopsies:()),
4950
//~^ NOTE macros cannot expand to struct fields
5051
//~| ERROR unexpected token: `!`
5152
//~| unexpected token after this
5253
field!(oopsies2:()),
53-
//~^ NOTE macros cannot expand to struct fields
54-
//~| ERROR unexpected token: `!`
55-
//~| unexpected token after this
5654
},
5755
}
5856

5957
union Union {
58+
//~^ NOTE while parsing this union
6059
A: u32,
6160
field!(oopsies:()),
6261
//~^ NOTE macros cannot expand to union fields
6362
//~| ERROR unexpected token: `!`
64-
//~| unexpected token after this
63+
//~| NOTE unexpected token after this
6564
B: u32,
6665
field!(recovers:()),
67-
//~^ NOTE macros cannot expand to union fields
66+
}
67+
68+
// https://github.com/rust-lang/rust/issues/114636
69+
70+
#[derive(Debug)]
71+
pub struct Lazy {
72+
//~^ NOTE while parsing this struct
73+
unreachable!()
74+
//~^ NOTE macros cannot expand to struct fields
6875
//~| ERROR unexpected token: `!`
69-
//~| unexpected token after this
76+
//~| NOTE unexpected token after this
7077
}
78+
79+
fn main() {}
Lines changed: 24 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,74 +1,71 @@
11
error: unexpected token: `!`
2-
--> $DIR/macro-expand-to-field.rs:16:10
2+
--> $DIR/macro-expand-to-field.rs:19:10
33
|
4+
LL | struct Struct {
5+
| ------ while parsing this struct
6+
LL |
47
LL | field!(bar:u128),
58
| ^ unexpected token after this
69
|
710
= note: macros cannot expand to struct fields
811

912
error: unexpected token: `!`
10-
--> $DIR/macro-expand-to-field.rs:22:10
11-
|
12-
LL | field!(recovers:()),
13-
| ^ unexpected token after this
14-
|
15-
= note: macros cannot expand to struct fields
16-
17-
error: unexpected token: `!`
18-
--> $DIR/macro-expand-to-field.rs:28:12
13+
--> $DIR/macro-expand-to-field.rs:29:12
1914
|
2015
LL | variant!(whoops),
2116
| ^ unexpected token after this
2217
|
2318
= note: macros cannot expand to enum variants
2419

2520
error: unexpected token: `!`
26-
--> $DIR/macro-expand-to-field.rs:34:12
21+
--> $DIR/macro-expand-to-field.rs:35:12
2722
|
2823
LL | variant!(recovers),
2924
| ^ unexpected token after this
3025
|
3126
= note: macros cannot expand to enum variants
3227

3328
error: unexpected token: `!`
34-
--> $DIR/macro-expand-to-field.rs:39:14
29+
--> $DIR/macro-expand-to-field.rs:40:14
3530
|
31+
LL | Data {
32+
| ---- while parsing this struct
3633
LL | field!(x:u32),
3734
| ^ unexpected token after this
3835
|
3936
= note: macros cannot expand to struct fields
4037

4138
error: unexpected token: `!`
42-
--> $DIR/macro-expand-to-field.rs:48:14
39+
--> $DIR/macro-expand-to-field.rs:49:14
4340
|
41+
LL | Named {
42+
| ----- while parsing this struct
4443
LL | field!(oopsies:()),
4544
| ^ unexpected token after this
4645
|
4746
= note: macros cannot expand to struct fields
4847

4948
error: unexpected token: `!`
50-
--> $DIR/macro-expand-to-field.rs:52:14
51-
|
52-
LL | field!(oopsies2:()),
53-
| ^ unexpected token after this
54-
|
55-
= note: macros cannot expand to struct fields
56-
57-
error: unexpected token: `!`
58-
--> $DIR/macro-expand-to-field.rs:61:10
49+
--> $DIR/macro-expand-to-field.rs:60:10
5950
|
51+
LL | union Union {
52+
| ----- while parsing this union
53+
...
6054
LL | field!(oopsies:()),
6155
| ^ unexpected token after this
6256
|
6357
= note: macros cannot expand to union fields
6458

6559
error: unexpected token: `!`
66-
--> $DIR/macro-expand-to-field.rs:66:10
60+
--> $DIR/macro-expand-to-field.rs:73:16
6761
|
68-
LL | field!(recovers:()),
69-
| ^ unexpected token after this
62+
LL | pub struct Lazy {
63+
| ---- while parsing this struct
64+
LL |
65+
LL | unreachable!()
66+
| ^ unexpected token after this
7067
|
71-
= note: macros cannot expand to union fields
68+
= note: macros cannot expand to struct fields
7269

73-
error: aborting due to 9 previous errors
70+
error: aborting due to 7 previous errors
7471

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
//~ ERROR overflow evaluating the requirement `Self well-formed`
2+
//~| ERROR overflow evaluating the requirement `Self: Trait`
3+
4+
// This is a non-regression test for issue #115351, where a recursion limit of 0 caused an ICE.
5+
// compile-flags: -Ztrait-solver=next --crate-type=lib
6+
// check-fail
7+
8+
#![recursion_limit = "0"]
9+
trait Trait {}
10+
impl Trait for u32 {}
11+
//~^ ERROR overflow evaluating the requirement `u32: Trait`
12+
//~| ERROR overflow evaluating the requirement `u32 well-formed`
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
error[E0275]: overflow evaluating the requirement `Self: Trait`
2+
|
3+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`recursion_limit_zero_issue_115351`)
4+
5+
error[E0275]: overflow evaluating the requirement `Self well-formed`
6+
|
7+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`recursion_limit_zero_issue_115351`)
8+
9+
error[E0275]: overflow evaluating the requirement `u32: Trait`
10+
--> $DIR/recursion-limit-zero-issue-115351.rs:10:16
11+
|
12+
LL | impl Trait for u32 {}
13+
| ^^^
14+
|
15+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`recursion_limit_zero_issue_115351`)
16+
17+
error[E0275]: overflow evaluating the requirement `u32 well-formed`
18+
--> $DIR/recursion-limit-zero-issue-115351.rs:10:16
19+
|
20+
LL | impl Trait for u32 {}
21+
| ^^^
22+
|
23+
= help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`recursion_limit_zero_issue_115351`)
24+
25+
error: aborting due to 4 previous errors
26+
27+
For more information about this error, try `rustc --explain E0275`.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Regression test for #114918
2+
// Test that a const generic enclosed in a block within a return type
3+
// produces a type mismatch error instead of triggering a const eval cycle
4+
5+
#[allow(unused_braces)]
6+
fn func() -> [u8; { () } ] { //~ ERROR mismatched types
7+
loop {}
8+
}
9+
10+
fn main() {}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/const-in-fn-return-type.rs:6:21
3+
|
4+
LL | fn func() -> [u8; { () } ] {
5+
| ^^ expected `usize`, found `()`
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0308`.
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Regression test for #114918
2+
// Test that a const generic enclosed in a block within the return type
3+
// of an impl fn produces a type mismatch error instead of triggering
4+
// a const eval cycle
5+
6+
7+
trait Trait {
8+
fn func<const N: u32>() -> [ (); N ];
9+
}
10+
11+
struct S {}
12+
13+
#[allow(unused_braces)]
14+
impl Trait for S {
15+
fn func<const N: u32>() -> [ (); { () }] { //~ ERROR mismatched types
16+
N
17+
}
18+
}
19+
20+
fn main() {}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/const-in-impl-fn-return-type.rs:15:40
3+
|
4+
LL | fn func<const N: u32>() -> [ (); { () }] {
5+
| ^^ expected `usize`, found `()`
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0308`.
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// Regression test for #114918
2+
// Test that a const generic enclosed in a block in a struct's type arg
3+
// produces a type mismatch error instead of triggering a const eval cycle
4+
5+
#[allow(unused_braces)]
6+
struct S<const N: usize> {
7+
arr: [u8; N]
8+
}
9+
10+
fn main() {
11+
let s = S::<{ () }> { arr: [5, 6, 7]}; //~ ERROR mismatched types
12+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/const-in-struct-type-arg.rs:11:19
3+
|
4+
LL | let s = S::<{ () }> { arr: [5, 6, 7]};
5+
| ^^ expected `usize`, found `()`
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0308`.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Regression test for #114918
2+
// Test that a const generic enclosed in a block within the return type
3+
// of a trait method produces a type mismatch error instead of triggering
4+
// a const eval cycle
5+
6+
#[allow(unused_braces)]
7+
trait Trait {
8+
fn func<const N: u32>() -> [ (); { () }] { //~ ERROR mismatched types
9+
N
10+
}
11+
}
12+
13+
fn main() {}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
error[E0308]: mismatched types
2+
--> $DIR/const-in-trait-fn-return-type.rs:8:40
3+
|
4+
LL | fn func<const N: u32>() -> [ (); { () }] {
5+
| ^^ expected `usize`, found `()`
6+
7+
error: aborting due to previous error
8+
9+
For more information about this error, try `rustc --explain E0308`.

0 commit comments

Comments
 (0)
Please sign in to comment.