about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-08-30 06:16:17 +0000
committerbors <bors@rust-lang.org>2023-08-30 06:16:17 +0000
commit7659abc63d33223fa366c8781c81698e28a21e6c (patch)
tree466c82b0bd0bf04f17096ce9f495ae6ac4a3515d
parent82c2eb48ee275638b437fa2a044e9d44de0ca0c6 (diff)
parentea2347843c24a59367952b0463505539f1b69a93 (diff)
downloadrust-7659abc63d33223fa366c8781c81698e28a21e6c.tar.gz
rust-7659abc63d33223fa366c8781c81698e28a21e6c.zip
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
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs23
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs3
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs7
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs75
-rw-r--r--compiler/rustc_driver_impl/src/signal_handler.rs142
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs3
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs13
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs3
-rw-r--r--compiler/rustc_parse/src/parser/item.rs16
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs38
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph/mod.rs6
-rw-r--r--src/tools/miri/src/diagnostics.rs65
-rw-r--r--tests/ui/associated-type-bounds/suggest-removing-impl.rs14
-rw-r--r--tests/ui/associated-type-bounds/suggest-removing-impl.stderr26
-rw-r--r--tests/ui/error-codes/E0609-private-method.rs16
-rw-r--r--tests/ui/error-codes/E0609-private-method.stderr9
-rw-r--r--tests/ui/parser/macro/macro-expand-to-field.rs31
-rw-r--r--tests/ui/parser/macro/macro-expand-to-field.stderr51
-rw-r--r--tests/ui/traits/new-solver/overflow/recursion-limit-zero-issue-115351.rs12
-rw-r--r--tests/ui/traits/new-solver/overflow/recursion-limit-zero-issue-115351.stderr27
-rw-r--r--tests/ui/typeck/issue-114918/const-in-fn-return-type.rs10
-rw-r--r--tests/ui/typeck/issue-114918/const-in-fn-return-type.stderr9
-rw-r--r--tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs20
-rw-r--r--tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr9
-rw-r--r--tests/ui/typeck/issue-114918/const-in-struct-type-arg.rs12
-rw-r--r--tests/ui/typeck/issue-114918/const-in-struct-type-arg.stderr9
-rw-r--r--tests/ui/typeck/issue-114918/const-in-trait-fn-return-type.rs13
-rw-r--r--tests/ui/typeck/issue-114918/const-in-trait-fn-return-type.stderr9
30 files changed, 498 insertions, 188 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(),
         }
diff --git a/src/tools/miri/src/diagnostics.rs b/src/tools/miri/src/diagnostics.rs
index f3285ccf917..799a9a8e4be 100644
--- a/src/tools/miri/src/diagnostics.rs
+++ b/src/tools/miri/src/diagnostics.rs
@@ -1,9 +1,8 @@
-use std::fmt;
+use std::fmt::{self, Write};
 use std::num::NonZeroU64;
 
 use log::trace;
 
-use rustc_const_eval::ReportErrorExt;
 use rustc_errors::DiagnosticMessage;
 use rustc_span::{source_map::DUMMY_SP, SpanData, Symbol};
 use rustc_target::abi::{Align, Size};
@@ -271,10 +270,13 @@ pub fn report_error<'tcx, 'mir>(
         };
         (title, helps)
     } else {
-        #[rustfmt::skip]
         let title = match e.kind() {
-            UndefinedBehavior(UndefinedBehaviorInfo::ValidationError(e)) if matches!(e.kind, ValidationErrorKind::PointerAsInt { .. } | ValidationErrorKind::PartialPointer) =>
-                bug!("This validation error should be impossible in Miri: {:?}", e.kind),
+            UndefinedBehavior(UndefinedBehaviorInfo::ValidationError(validation_err))
+                if matches!(validation_err.kind, ValidationErrorKind::PointerAsInt { .. } | ValidationErrorKind::PartialPointer) =>
+            {
+                ecx.handle_ice(); // print interpreter backtrace
+                bug!("This validation error should be impossible in Miri: {}", ecx.format_error(e));
+            }
             UndefinedBehavior(_) =>
                 "Undefined Behavior",
             ResourceExhaustion(_) =>
@@ -290,8 +292,10 @@ pub fn report_error<'tcx, 'mir>(
                 InvalidProgramInfo::Layout(..)
             ) =>
                 "post-monomorphization error",
-            kind =>
-                bug!("This error should be impossible in Miri: {kind:?}"),
+            _ => {
+                ecx.handle_ice(); // print interpreter backtrace
+                bug!("This error should be impossible in Miri: {}", ecx.format_error(e));
+            }
         };
         #[rustfmt::skip]
         let helps = match e.kind() {
@@ -333,30 +337,22 @@ pub fn report_error<'tcx, 'mir>(
 
     let stacktrace = ecx.generate_stacktrace();
     let (stacktrace, was_pruned) = prune_stacktrace(stacktrace, &ecx.machine);
-    let (e, backtrace) = e.into_parts();
-    backtrace.print_backtrace();
-
-    // We want to dump the allocation if this is `InvalidUninitBytes`. Since `add_args` consumes
-    // the `InterpError`, we extract the variables it before that.
-    let extra = match e {
-        UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) =>
-            Some((alloc_id, access)),
-        _ => None,
-    };
 
-    // 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 e = {
-        let handler = &ecx.tcx.sess.parse_sess.span_diagnostic;
-        let mut diag = ecx.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
-    };
+    // We want to dump the allocation if this is `InvalidUninitBytes`. Since `format_error` consumes `e`, we compute the outut early.
+    let mut extra = String::new();
+    match e.kind() {
+        UndefinedBehavior(UndefinedBehaviorInfo::InvalidUninitBytes(Some((alloc_id, access)))) => {
+            writeln!(
+                extra,
+                "Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:",
+                range = access.bad,
+            ).unwrap();
+            writeln!(extra, "{:?}", ecx.dump_alloc(*alloc_id)).unwrap();
+        }
+        _ => {}
+    }
 
-    msg.insert(0, e);
+    msg.insert(0, ecx.format_error(e));
 
     report_msg(
         DiagLevel::Error,
@@ -375,6 +371,8 @@ pub fn report_error<'tcx, 'mir>(
         );
     }
 
+    eprint!("{extra}"); // newlines are already in the string
+
     // Debug-dump all locals.
     for (i, frame) in ecx.active_thread_stack().iter().enumerate() {
         trace!("-------------------");
@@ -385,15 +383,6 @@ pub fn report_error<'tcx, 'mir>(
         }
     }
 
-    // Extra output to help debug specific issues.
-    if let Some((alloc_id, access)) = extra {
-        eprintln!(
-            "Uninitialized memory occurred at {alloc_id:?}{range:?}, in this allocation:",
-            range = access.bad,
-        );
-        eprintln!("{:?}", ecx.dump_alloc(alloc_id));
-    }
-
     None
 }
 
diff --git a/tests/ui/associated-type-bounds/suggest-removing-impl.rs b/tests/ui/associated-type-bounds/suggest-removing-impl.rs
new file mode 100644
index 00000000000..242cd85727d
--- /dev/null
+++ b/tests/ui/associated-type-bounds/suggest-removing-impl.rs
@@ -0,0 +1,14 @@
+trait Tr {
+    type Assoc: impl Sized;
+    //~^ ERROR expected a trait, found type
+    //~| HELP use the trait bounds directly
+
+    fn fn_with_generics<T>()
+    where
+        T: impl Sized
+        //~^ ERROR expected a trait, found type
+        //~| HELP use the trait bounds directly
+    {}
+}
+
+fn main() {}
diff --git a/tests/ui/associated-type-bounds/suggest-removing-impl.stderr b/tests/ui/associated-type-bounds/suggest-removing-impl.stderr
new file mode 100644
index 00000000000..875b2db6deb
--- /dev/null
+++ b/tests/ui/associated-type-bounds/suggest-removing-impl.stderr
@@ -0,0 +1,26 @@
+error: expected a trait, found type
+  --> $DIR/suggest-removing-impl.rs:2:17
+   |
+LL |     type Assoc: impl Sized;
+   |                 ^^^^^^^^^^
+   |
+help: use the trait bounds directly
+   |
+LL -     type Assoc: impl Sized;
+LL +     type Assoc: Sized;
+   |
+
+error: expected a trait, found type
+  --> $DIR/suggest-removing-impl.rs:8:12
+   |
+LL |         T: impl Sized
+   |            ^^^^^^^^^^
+   |
+help: use the trait bounds directly
+   |
+LL -         T: impl Sized
+LL +         T: Sized
+   |
+
+error: aborting due to 2 previous errors
+
diff --git a/tests/ui/error-codes/E0609-private-method.rs b/tests/ui/error-codes/E0609-private-method.rs
new file mode 100644
index 00000000000..dfa97ad9a6f
--- /dev/null
+++ b/tests/ui/error-codes/E0609-private-method.rs
@@ -0,0 +1,16 @@
+// This error is an E0609 and *not* an E0615 because the fact that the method exists is not
+// relevant.
+mod foo {
+    pub struct Foo {
+        x: u32,
+    }
+
+    impl Foo {
+        fn method(&self) {}
+    }
+}
+
+fn main() {
+    let f = foo::Foo { x: 0 };
+    f.method; //~ ERROR E0609
+}
diff --git a/tests/ui/error-codes/E0609-private-method.stderr b/tests/ui/error-codes/E0609-private-method.stderr
new file mode 100644
index 00000000000..d2a11e90627
--- /dev/null
+++ b/tests/ui/error-codes/E0609-private-method.stderr
@@ -0,0 +1,9 @@
+error[E0609]: no field `method` on type `Foo`
+  --> $DIR/E0609-private-method.rs:15:7
+   |
+LL |     f.method;
+   |       ^^^^^^ unknown field
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0609`.
diff --git a/tests/ui/parser/macro/macro-expand-to-field.rs b/tests/ui/parser/macro/macro-expand-to-field.rs
index 155872f7a5d..533511ecf5a 100644
--- a/tests/ui/parser/macro/macro-expand-to-field.rs
+++ b/tests/ui/parser/macro/macro-expand-to-field.rs
@@ -1,5 +1,7 @@
 // compile-flags: --crate-type=lib
 
+// https://github.com/rust-lang/rust/issues/113766
+
 macro_rules! field {
     ($name:ident:$type:ty) => {
         $name:$type
@@ -13,15 +15,14 @@ macro_rules! variant {
 }
 
 struct Struct {
+    //~^ NOTE while parsing this struct
     field!(bar:u128),
     //~^ NOTE macros cannot expand to struct fields
     //~| ERROR unexpected token: `!`
     //~| NOTE unexpected token after this
     a: u32,
     b: u32,
-    field!(recovers:()), //~ NOTE macros cannot expand to struct fields
-    //~^ ERROR unexpected token: `!`
-    //~^^ NOTE unexpected token after this
+    field!(recovers:()),
 }
 
 enum EnumVariant {
@@ -35,7 +36,7 @@ enum EnumVariant {
     //~^ NOTE macros cannot expand to enum variants
     //~| ERROR unexpected token: `!`
     //~| NOTE unexpected token after this
-    Data {
+    Data { //~ NOTE while parsing this struct
         field!(x:u32),
         //~^ NOTE macros cannot expand to struct fields
         //~| ERROR unexpected token: `!`
@@ -44,27 +45,35 @@ enum EnumVariant {
 }
 
 enum EnumVariantField {
-    Named {
+    Named { //~ NOTE while parsing this struct
         field!(oopsies:()),
         //~^ NOTE macros cannot expand to struct fields
         //~| ERROR unexpected token: `!`
         //~| unexpected token after this
         field!(oopsies2:()),
-        //~^ NOTE macros cannot expand to struct fields
-        //~| ERROR unexpected token: `!`
-        //~| unexpected token after this
     },
 }
 
 union Union {
+    //~^ NOTE while parsing this union
     A: u32,
     field!(oopsies:()),
     //~^ NOTE macros cannot expand to union fields
     //~| ERROR unexpected token: `!`
-    //~| unexpected token after this
+    //~| NOTE unexpected token after this
     B: u32,
     field!(recovers:()),
-    //~^ NOTE macros cannot expand to union fields
+}
+
+// https://github.com/rust-lang/rust/issues/114636
+
+#[derive(Debug)]
+pub struct Lazy {
+    //~^ NOTE while parsing this struct
+    unreachable!()
+    //~^ NOTE macros cannot expand to struct fields
     //~| ERROR unexpected token: `!`
-    //~| unexpected token after this
+    //~| NOTE unexpected token after this
 }
+
+fn main() {}
diff --git a/tests/ui/parser/macro/macro-expand-to-field.stderr b/tests/ui/parser/macro/macro-expand-to-field.stderr
index adcd032f5c0..0bb71800081 100644
--- a/tests/ui/parser/macro/macro-expand-to-field.stderr
+++ b/tests/ui/parser/macro/macro-expand-to-field.stderr
@@ -1,21 +1,16 @@
 error: unexpected token: `!`
-  --> $DIR/macro-expand-to-field.rs:16:10
+  --> $DIR/macro-expand-to-field.rs:19:10
    |
+LL | struct Struct {
+   |        ------ while parsing this struct
+LL |
 LL |     field!(bar:u128),
    |          ^ unexpected token after this
    |
    = note: macros cannot expand to struct fields
 
 error: unexpected token: `!`
-  --> $DIR/macro-expand-to-field.rs:22:10
-   |
-LL |     field!(recovers:()),
-   |          ^ unexpected token after this
-   |
-   = note: macros cannot expand to struct fields
-
-error: unexpected token: `!`
-  --> $DIR/macro-expand-to-field.rs:28:12
+  --> $DIR/macro-expand-to-field.rs:29:12
    |
 LL |     variant!(whoops),
    |            ^ unexpected token after this
@@ -23,7 +18,7 @@ LL |     variant!(whoops),
    = note: macros cannot expand to enum variants
 
 error: unexpected token: `!`
-  --> $DIR/macro-expand-to-field.rs:34:12
+  --> $DIR/macro-expand-to-field.rs:35:12
    |
 LL |     variant!(recovers),
    |            ^ unexpected token after this
@@ -31,44 +26,46 @@ LL |     variant!(recovers),
    = note: macros cannot expand to enum variants
 
 error: unexpected token: `!`
-  --> $DIR/macro-expand-to-field.rs:39:14
+  --> $DIR/macro-expand-to-field.rs:40:14
    |
+LL |     Data {
+   |     ---- while parsing this struct
 LL |         field!(x:u32),
    |              ^ unexpected token after this
    |
    = note: macros cannot expand to struct fields
 
 error: unexpected token: `!`
-  --> $DIR/macro-expand-to-field.rs:48:14
+  --> $DIR/macro-expand-to-field.rs:49:14
    |
+LL |     Named {
+   |     ----- while parsing this struct
 LL |         field!(oopsies:()),
    |              ^ unexpected token after this
    |
    = note: macros cannot expand to struct fields
 
 error: unexpected token: `!`
-  --> $DIR/macro-expand-to-field.rs:52:14
-   |
-LL |         field!(oopsies2:()),
-   |              ^ unexpected token after this
-   |
-   = note: macros cannot expand to struct fields
-
-error: unexpected token: `!`
-  --> $DIR/macro-expand-to-field.rs:61:10
+  --> $DIR/macro-expand-to-field.rs:60:10
    |
+LL | union Union {
+   |       ----- while parsing this union
+...
 LL |     field!(oopsies:()),
    |          ^ unexpected token after this
    |
    = note: macros cannot expand to union fields
 
 error: unexpected token: `!`
-  --> $DIR/macro-expand-to-field.rs:66:10
+  --> $DIR/macro-expand-to-field.rs:73:16
    |
-LL |     field!(recovers:()),
-   |          ^ unexpected token after this
+LL | pub struct Lazy {
+   |            ---- while parsing this struct
+LL |
+LL |     unreachable!()
+   |                ^ unexpected token after this
    |
-   = note: macros cannot expand to union fields
+   = note: macros cannot expand to struct fields
 
-error: aborting due to 9 previous errors
+error: aborting due to 7 previous errors
 
diff --git a/tests/ui/traits/new-solver/overflow/recursion-limit-zero-issue-115351.rs b/tests/ui/traits/new-solver/overflow/recursion-limit-zero-issue-115351.rs
new file mode 100644
index 00000000000..539c9614e82
--- /dev/null
+++ b/tests/ui/traits/new-solver/overflow/recursion-limit-zero-issue-115351.rs
@@ -0,0 +1,12 @@
+//~ ERROR overflow evaluating the requirement `Self well-formed`
+//~| ERROR overflow evaluating the requirement `Self: Trait`
+
+// This is a non-regression test for issue #115351, where a recursion limit of 0 caused an ICE.
+// compile-flags: -Ztrait-solver=next --crate-type=lib
+// check-fail
+
+#![recursion_limit = "0"]
+trait Trait {}
+impl Trait for u32 {}
+//~^ ERROR overflow evaluating the requirement `u32: Trait`
+//~| ERROR overflow evaluating the requirement `u32 well-formed`
diff --git a/tests/ui/traits/new-solver/overflow/recursion-limit-zero-issue-115351.stderr b/tests/ui/traits/new-solver/overflow/recursion-limit-zero-issue-115351.stderr
new file mode 100644
index 00000000000..16b25d90ace
--- /dev/null
+++ b/tests/ui/traits/new-solver/overflow/recursion-limit-zero-issue-115351.stderr
@@ -0,0 +1,27 @@
+error[E0275]: overflow evaluating the requirement `Self: Trait`
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`recursion_limit_zero_issue_115351`)
+
+error[E0275]: overflow evaluating the requirement `Self well-formed`
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`recursion_limit_zero_issue_115351`)
+
+error[E0275]: overflow evaluating the requirement `u32: Trait`
+  --> $DIR/recursion-limit-zero-issue-115351.rs:10:16
+   |
+LL | impl Trait for u32 {}
+   |                ^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`recursion_limit_zero_issue_115351`)
+
+error[E0275]: overflow evaluating the requirement `u32 well-formed`
+  --> $DIR/recursion-limit-zero-issue-115351.rs:10:16
+   |
+LL | impl Trait for u32 {}
+   |                ^^^
+   |
+   = help: consider increasing the recursion limit by adding a `#![recursion_limit = "2"]` attribute to your crate (`recursion_limit_zero_issue_115351`)
+
+error: aborting due to 4 previous errors
+
+For more information about this error, try `rustc --explain E0275`.
diff --git a/tests/ui/typeck/issue-114918/const-in-fn-return-type.rs b/tests/ui/typeck/issue-114918/const-in-fn-return-type.rs
new file mode 100644
index 00000000000..d939633290e
--- /dev/null
+++ b/tests/ui/typeck/issue-114918/const-in-fn-return-type.rs
@@ -0,0 +1,10 @@
+// Regression test for #114918
+// Test that a const generic enclosed in a block within a return type
+// produces a type mismatch error instead of triggering a const eval cycle
+
+#[allow(unused_braces)]
+fn func() -> [u8; { () } ] { //~ ERROR mismatched types
+    loop {}
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/issue-114918/const-in-fn-return-type.stderr b/tests/ui/typeck/issue-114918/const-in-fn-return-type.stderr
new file mode 100644
index 00000000000..88ed96e148c
--- /dev/null
+++ b/tests/ui/typeck/issue-114918/const-in-fn-return-type.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/const-in-fn-return-type.rs:6:21
+   |
+LL | fn func() -> [u8; { () } ] {
+   |                     ^^ expected `usize`, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs
new file mode 100644
index 00000000000..a1b9a7eba4d
--- /dev/null
+++ b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.rs
@@ -0,0 +1,20 @@
+// Regression test for #114918
+// Test that a const generic enclosed in a block within the return type
+// of an impl fn produces a type mismatch error instead of triggering
+// a const eval cycle
+
+
+trait Trait {
+    fn func<const N: u32>() -> [ (); N ];
+}
+
+struct S {}
+
+#[allow(unused_braces)]
+impl Trait for S {
+    fn func<const N: u32>() -> [ (); { () }] { //~ ERROR mismatched types
+        N
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr
new file mode 100644
index 00000000000..9843651b1e6
--- /dev/null
+++ b/tests/ui/typeck/issue-114918/const-in-impl-fn-return-type.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/const-in-impl-fn-return-type.rs:15:40
+   |
+LL |     fn func<const N: u32>() -> [ (); { () }] {
+   |                                        ^^ expected `usize`, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/typeck/issue-114918/const-in-struct-type-arg.rs b/tests/ui/typeck/issue-114918/const-in-struct-type-arg.rs
new file mode 100644
index 00000000000..9eee4ab3d4c
--- /dev/null
+++ b/tests/ui/typeck/issue-114918/const-in-struct-type-arg.rs
@@ -0,0 +1,12 @@
+// Regression test for #114918
+// Test that a const generic enclosed in a block in a struct's type arg
+// produces a type mismatch error instead of triggering a const eval cycle
+
+#[allow(unused_braces)]
+struct S<const N: usize> {
+        arr: [u8; N]
+}
+
+fn main() {
+    let s = S::<{ () }> { arr: [5, 6, 7]}; //~ ERROR mismatched types
+}
diff --git a/tests/ui/typeck/issue-114918/const-in-struct-type-arg.stderr b/tests/ui/typeck/issue-114918/const-in-struct-type-arg.stderr
new file mode 100644
index 00000000000..3307e76d957
--- /dev/null
+++ b/tests/ui/typeck/issue-114918/const-in-struct-type-arg.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/const-in-struct-type-arg.rs:11:19
+   |
+LL |     let s = S::<{ () }> { arr: [5, 6, 7]};
+   |                   ^^ expected `usize`, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.
diff --git a/tests/ui/typeck/issue-114918/const-in-trait-fn-return-type.rs b/tests/ui/typeck/issue-114918/const-in-trait-fn-return-type.rs
new file mode 100644
index 00000000000..8e2eec34911
--- /dev/null
+++ b/tests/ui/typeck/issue-114918/const-in-trait-fn-return-type.rs
@@ -0,0 +1,13 @@
+// Regression test for #114918
+// Test that a const generic enclosed in a block within the return type
+// of a trait method produces a type mismatch error instead of triggering
+// a const eval cycle
+
+#[allow(unused_braces)]
+trait Trait {
+    fn func<const N: u32>() -> [ (); { () }] { //~ ERROR mismatched types
+        N
+    }
+}
+
+fn main() {}
diff --git a/tests/ui/typeck/issue-114918/const-in-trait-fn-return-type.stderr b/tests/ui/typeck/issue-114918/const-in-trait-fn-return-type.stderr
new file mode 100644
index 00000000000..6bc0de77a62
--- /dev/null
+++ b/tests/ui/typeck/issue-114918/const-in-trait-fn-return-type.stderr
@@ -0,0 +1,9 @@
+error[E0308]: mismatched types
+  --> $DIR/const-in-trait-fn-return-type.rs:8:40
+   |
+LL |     fn func<const N: u32>() -> [ (); { () }] {
+   |                                        ^^ expected `usize`, found `()`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0308`.