about summary refs log tree commit diff
path: root/compiler
diff options
context:
space:
mode:
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs62
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs76
-rw-r--r--compiler/rustc_errors/src/lib.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs29
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs43
-rw-r--r--compiler/rustc_infer/src/traits/engine.rs4
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs6
-rw-r--r--compiler/rustc_infer/src/traits/structural_impls.rs3
-rw-r--r--compiler/rustc_lexer/src/lib.rs43
-rw-r--r--compiler/rustc_lexer/src/tests.rs2
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs9
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs29
-rw-r--r--compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs7
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs15
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs11
17 files changed, 196 insertions, 149 deletions
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index a76ed4ee6ce..79d8be2484b 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -118,34 +118,22 @@ pub fn expand_test_or_bench(
             }
         }
         other => {
-            cx.struct_span_err(
-                other.span(),
-                "`#[test]` attribute is only allowed on non associated functions",
-            )
-            .emit();
+            not_testable_error(cx, attr_sp, None);
             return vec![other];
         }
     };
 
-    // Note: non-associated fn items are already handled by `expand_test_or_bench`
     let ast::ItemKind::Fn(fn_) = &item.kind else {
-        let diag = &cx.sess.parse_sess.span_diagnostic;
-        let msg = "the `#[test]` attribute may only be used on a non-associated function";
-        let mut err = match item.kind {
-            // These were a warning before #92959 and need to continue being that to avoid breaking
-            // stable user code (#94508).
-            ast::ItemKind::MacCall(_) => diag.struct_span_warn(attr_sp, msg),
-            // `.forget_guarantee()` needed to get these two arms to match types. Because of how
-            // locally close the `.emit()` call is I'm comfortable with it, but if it can be
-            // reworked in the future to not need it, it'd be nice.
-            _ => diag.struct_span_err(attr_sp, msg).forget_guarantee(),
+        not_testable_error(cx, attr_sp, Some(&item));
+        return if is_stmt {
+            vec![Annotatable::Stmt(P(ast::Stmt {
+                id: ast::DUMMY_NODE_ID,
+                span: item.span,
+                kind: ast::StmtKind::Item(item),
+            }))]
+        } else {
+            vec![Annotatable::Item(item)]
         };
-        err.span_label(attr_sp, "the `#[test]` macro causes a function to be run on a test and has no effect on non-functions")
-            .span_label(item.span, format!("expected a non-associated function, found {} {}", item.kind.article(), item.kind.descr()))
-            .span_suggestion(attr_sp, "replace with conditional compilation to make the item only exist when tests are being run", "#[cfg(test)]", Applicability::MaybeIncorrect)
-            .emit();
-
-        return vec![Annotatable::Item(item)];
     };
 
     // has_*_signature will report any errors in the type so compilation
@@ -398,6 +386,36 @@ pub fn expand_test_or_bench(
     }
 }
 
+fn not_testable_error(cx: &ExtCtxt<'_>, attr_sp: Span, item: Option<&ast::Item>) {
+    let diag = &cx.sess.parse_sess.span_diagnostic;
+    let msg = "the `#[test]` attribute may only be used on a non-associated function";
+    let mut err = match item.map(|i| &i.kind) {
+        // These were a warning before #92959 and need to continue being that to avoid breaking
+        // stable user code (#94508).
+        Some(ast::ItemKind::MacCall(_)) => diag.struct_span_warn(attr_sp, msg),
+        // `.forget_guarantee()` needed to get these two arms to match types. Because of how
+        // locally close the `.emit()` call is I'm comfortable with it, but if it can be
+        // reworked in the future to not need it, it'd be nice.
+        _ => diag.struct_span_err(attr_sp, msg).forget_guarantee(),
+    };
+    if let Some(item) = item {
+        err.span_label(
+            item.span,
+            format!(
+                "expected a non-associated function, found {} {}",
+                item.kind.article(),
+                item.kind.descr()
+            ),
+        );
+    }
+    err.span_label(attr_sp, "the `#[test]` macro causes a function to be run as a test and has no effect on non-functions")
+        .span_suggestion(attr_sp,
+            "replace with conditional compilation to make the item only exist when tests are being run",
+            "#[cfg(test)]",
+            Applicability::MaybeIncorrect)
+        .emit();
+}
+
 fn get_location_info(cx: &ExtCtxt<'_>, item: &ast::Item) -> (Symbol, usize, usize, usize, usize) {
     let span = item.ident.span;
     let (source_file, lo_line, lo_col, hi_line, hi_col) =
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index 730d41ab962..634d06da7f5 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -37,7 +37,7 @@ use rustc_metadata::locator;
 use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
 use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths};
 use rustc_session::cstore::MetadataLoader;
-use rustc_session::getopts;
+use rustc_session::getopts::{self, Matches};
 use rustc_session::lint::{Lint, LintId};
 use rustc_session::{config, Session};
 use rustc_session::{early_error, early_error_no_abort, early_warn};
@@ -956,6 +956,46 @@ Available lint options:
     }
 }
 
+/// Show help for flag categories shared between rustdoc and rustc.
+///
+/// Returns whether a help option was printed.
+pub fn describe_flag_categories(matches: &Matches) -> bool {
+    // Handle the special case of -Wall.
+    let wall = matches.opt_strs("W");
+    if wall.iter().any(|x| *x == "all") {
+        print_wall_help();
+        rustc_errors::FatalError.raise();
+    }
+
+    // Don't handle -W help here, because we might first load plugins.
+    let debug_flags = matches.opt_strs("Z");
+    if debug_flags.iter().any(|x| *x == "help") {
+        describe_debug_flags();
+        return true;
+    }
+
+    let cg_flags = matches.opt_strs("C");
+    if cg_flags.iter().any(|x| *x == "help") {
+        describe_codegen_flags();
+        return true;
+    }
+
+    if cg_flags.iter().any(|x| *x == "no-stack-check") {
+        early_warn(
+            ErrorOutputType::default(),
+            "the --no-stack-check flag is deprecated and does nothing",
+        );
+    }
+
+    if cg_flags.iter().any(|x| *x == "passes=list") {
+        let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
+        get_codegen_backend(&None, backend_name).print_passes();
+        return true;
+    }
+
+    false
+}
+
 fn describe_debug_flags() {
     println!("\nAvailable options:\n");
     print_flag_list("-Z", config::Z_OPTIONS);
@@ -966,7 +1006,7 @@ fn describe_codegen_flags() {
     print_flag_list("-C", config::CG_OPTIONS);
 }
 
-pub fn print_flag_list<T>(
+fn print_flag_list<T>(
     cmdline_opt: &str,
     flag_list: &[(&'static str, T, &'static str, &'static str)],
 ) {
@@ -1059,37 +1099,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
         return None;
     }
 
-    // Handle the special case of -Wall.
-    let wall = matches.opt_strs("W");
-    if wall.iter().any(|x| *x == "all") {
-        print_wall_help();
-        rustc_errors::FatalError.raise();
-    }
-
-    // Don't handle -W help here, because we might first load plugins.
-    let debug_flags = matches.opt_strs("Z");
-    if debug_flags.iter().any(|x| *x == "help") {
-        describe_debug_flags();
-        return None;
-    }
-
-    let cg_flags = matches.opt_strs("C");
-
-    if cg_flags.iter().any(|x| *x == "help") {
-        describe_codegen_flags();
-        return None;
-    }
-
-    if cg_flags.iter().any(|x| *x == "no-stack-check") {
-        early_warn(
-            ErrorOutputType::default(),
-            "the --no-stack-check flag is deprecated and does nothing",
-        );
-    }
-
-    if cg_flags.iter().any(|x| *x == "passes=list") {
-        let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
-        get_codegen_backend(&None, backend_name).print_passes();
+    if describe_flag_categories(&matches) {
         return None;
     }
 
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index 5b0d8096207..3bd1958a08a 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -475,8 +475,6 @@ pub enum StashKey {
     /// When an invalid lifetime e.g. `'2` should be reinterpreted
     /// as a char literal in the parser
     LifetimeIsChar,
-    /// When an invalid lifetime e.g. `'🐱` contains emoji.
-    LifetimeContainsEmoji,
     /// Maybe there was a typo where a comma was forgotten before
     /// FRU syntax
     MaybeFruTypo,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index fdf178c3ea7..f736f7a9620 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -578,7 +578,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
 
     #[instrument(skip(self), level = "debug")]
     pub(in super::super) fn report_ambiguity_errors(&self) {
-        let mut errors = self.fulfillment_cx.borrow_mut().collect_remaining_errors();
+        let mut errors = self.fulfillment_cx.borrow_mut().collect_remaining_errors(self);
 
         if !errors.is_empty() {
             self.adjust_fulfillment_errors_for_expr_obligation(&mut errors);
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index e887ab2fa14..f879ccbb3af 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -78,7 +78,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // Finally, for ambiguity-related errors, we actually want to look
         // for a parameter that is the source of the inference type left
         // over in this predicate.
-        if let traits::FulfillmentErrorCode::CodeAmbiguity = error.code {
+        if let traits::FulfillmentErrorCode::CodeAmbiguity { .. } = error.code {
             fallback_param_to_point_at = None;
             self_param_to_point_at = None;
             param_to_point_at =
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 08cd6085d7f..4fd778910ba 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -1531,23 +1531,18 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
 
                     // Convert the bounds into obligations.
                     let impl_obligations = traits::predicates_for_generics(
-                        |_idx, span| {
-                            let misc = traits::ObligationCause::misc(span, self.body_id);
-                            let parent_trait_pred = ty::Binder::dummy(ty::TraitPredicate {
-                                trait_ref: ty::TraitRef::from_method(self.tcx, impl_def_id, substs),
-                                constness: ty::BoundConstness::NotConst,
-                                polarity: ty::ImplPolarity::Positive,
-                            });
-                            misc.derived_cause(parent_trait_pred, |derived| {
-                                traits::ImplDerivedObligation(Box::new(
-                                    traits::ImplDerivedObligationCause {
-                                        derived,
-                                        impl_or_alias_def_id: impl_def_id,
-                                        impl_def_predicate_index: None,
-                                        span,
-                                    },
-                                ))
-                            })
+                        |idx, span| {
+                            let code = if span.is_dummy() {
+                                traits::ExprItemObligation(impl_def_id, self.scope_expr_id, idx)
+                            } else {
+                                traits::ExprBindingObligation(
+                                    impl_def_id,
+                                    span,
+                                    self.scope_expr_id,
+                                    idx,
+                                )
+                            };
+                            ObligationCause::new(self.span, self.body_id, code)
                         },
                         self.param_env,
                         impl_bounds,
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 7702a8b7004..900a6fa0d8d 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -661,19 +661,26 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
             // Find all the requirements that come from a local `impl` block.
             let mut skip_list: FxHashSet<_> = Default::default();
             let mut spanned_predicates = FxHashMap::default();
-            for (p, parent_p, impl_def_id, cause) in unsatisfied_predicates
-                .iter()
-                .filter_map(|(p, parent, c)| c.as_ref().map(|c| (p, parent, c)))
-                .filter_map(|(p, parent, c)| match c.code() {
-                    ObligationCauseCode::ImplDerivedObligation(data)
-                        if matches!(p.kind().skip_binder(), ty::PredicateKind::Clause(_)) =>
-                    {
-                        Some((p, parent, data.impl_or_alias_def_id, data))
+            for (p, parent_p, cause) in unsatisfied_predicates {
+                // Extract the predicate span and parent def id of the cause,
+                // if we have one.
+                let (item_def_id, cause_span) = match cause.as_ref().map(|cause| cause.code()) {
+                    Some(ObligationCauseCode::ImplDerivedObligation(data)) => {
+                        (data.impl_or_alias_def_id, data.span)
                     }
-                    _ => None,
-                })
-            {
-                match self.tcx.hir().get_if_local(impl_def_id) {
+                    Some(
+                        ObligationCauseCode::ExprBindingObligation(def_id, span, _, _)
+                        | ObligationCauseCode::BindingObligation(def_id, span),
+                    ) => (*def_id, *span),
+                    _ => continue,
+                };
+
+                // Don't point out the span of `WellFormed` predicates.
+                if !matches!(p.kind().skip_binder(), ty::PredicateKind::Clause(_)) {
+                    continue;
+                };
+
+                match self.tcx.hir().get_if_local(item_def_id) {
                     // Unmet obligation comes from a `derive` macro, point at it once to
                     // avoid multiple span labels pointing at the same place.
                     Some(Node::Item(hir::Item {
@@ -718,7 +725,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                                 }
                             });
                         for param in generics.params {
-                            if param.span == cause.span && sized_pred {
+                            if param.span == cause_span && sized_pred {
                                 let (sp, sugg) = match param.colon_span {
                                     Some(sp) => (sp.shrink_to_hi(), " ?Sized +"),
                                     None => (param.span.shrink_to_hi(), ": ?Sized"),
@@ -741,9 +748,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                             (FxHashSet::default(), FxHashSet::default(), Vec::new())
                         });
                         entry.2.push(p);
-                        if cause.span != *item_span {
-                            entry.0.insert(cause.span);
-                            entry.1.insert((cause.span, "unsatisfied trait bound introduced here"));
+                        if cause_span != *item_span {
+                            entry.0.insert(cause_span);
+                            entry.1.insert((cause_span, "unsatisfied trait bound introduced here"));
                         } else {
                             if let Some(trait_ref) = of_trait {
                                 entry.0.insert(trait_ref.path.span);
@@ -775,9 +782,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                         let entry = entry.or_insert_with(|| {
                             (FxHashSet::default(), FxHashSet::default(), Vec::new())
                         });
-                        entry.0.insert(cause.span);
+                        entry.0.insert(cause_span);
                         entry.1.insert((ident.span, ""));
-                        entry.1.insert((cause.span, "unsatisfied trait bound introduced here"));
+                        entry.1.insert((cause_span, "unsatisfied trait bound introduced here"));
                         entry.2.push(p);
                     }
                     Some(node) => unreachable!("encountered `{node:?}`"),
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index f75344f20b6..2f0a19b46de 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -38,7 +38,7 @@ pub trait TraitEngine<'tcx>: 'tcx {
 
     fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
 
-    fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>>;
+    fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>>;
 
     fn pending_obligations(&self) -> Vec<PredicateObligation<'tcx>>;
 
@@ -78,6 +78,6 @@ impl<'tcx, T: ?Sized + TraitEngine<'tcx>> TraitEngineExt<'tcx> for T {
             return errors;
         }
 
-        self.collect_remaining_errors()
+        self.collect_remaining_errors(infcx)
     }
 }
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index dd9b2e548c7..e01b6caf430 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -128,7 +128,11 @@ pub enum FulfillmentErrorCode<'tcx> {
     CodeProjectionError(MismatchedProjectionTypes<'tcx>),
     CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
     CodeConstEquateError(ExpectedFound<Const<'tcx>>, TypeError<'tcx>),
-    CodeAmbiguity,
+    CodeAmbiguity {
+        /// Overflow reported from the new solver `-Ztrait-solver=next`, which will
+        /// be reported as an regular error as opposed to a fatal error.
+        overflow: bool,
+    },
 }
 
 impl<'tcx, O> Obligation<'tcx, O> {
diff --git a/compiler/rustc_infer/src/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs
index 3a5273b0359..1563d92af0e 100644
--- a/compiler/rustc_infer/src/traits/structural_impls.rs
+++ b/compiler/rustc_infer/src/traits/structural_impls.rs
@@ -46,7 +46,8 @@ impl<'tcx> fmt::Debug for traits::FulfillmentErrorCode<'tcx> {
             super::CodeConstEquateError(ref a, ref b) => {
                 write!(f, "CodeConstEquateError({:?}, {:?})", a, b)
             }
-            super::CodeAmbiguity => write!(f, "Ambiguity"),
+            super::CodeAmbiguity { overflow: false } => write!(f, "Ambiguity"),
+            super::CodeAmbiguity { overflow: true } => write!(f, "Overflow"),
             super::CodeCycle(ref cycle) => write!(f, "Cycle({:?})", cycle),
         }
     }
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index 322ec31fb2c..b3f4b5cd5e5 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -95,7 +95,7 @@ pub enum TokenKind {
     Literal { kind: LiteralKind, suffix_start: u32 },
 
     /// "'a"
-    Lifetime { starts_with_number: bool, contains_emoji: bool },
+    Lifetime { starts_with_number: bool },
 
     // One-char tokens:
     /// ";"
@@ -632,13 +632,7 @@ impl Cursor<'_> {
             // If the first symbol is valid for identifier, it can be a lifetime.
             // Also check if it's a number for a better error reporting (so '0 will
             // be reported as invalid lifetime and not as unterminated char literal).
-            // We also have to account for potential `'🐱` emojis to avoid reporting
-            // it as an unterminated char literal.
-            is_id_start(self.first())
-                || self.first().is_digit(10)
-                // FIXME(#108019): `unic-emoji-char` seems to have data tables only up to Unicode
-                // 5.0, but Unicode is already newer than this.
-                || unic_emoji_char::is_emoji(self.first())
+            is_id_start(self.first()) || self.first().is_digit(10)
         };
 
         if !can_be_a_lifetime {
@@ -651,33 +645,16 @@ impl Cursor<'_> {
             return Literal { kind, suffix_start };
         }
 
-        // Either a lifetime or a character literal.
+        // Either a lifetime or a character literal with
+        // length greater than 1.
 
         let starts_with_number = self.first().is_digit(10);
-        let mut contains_emoji = false;
 
-        // FIXME(#108019): `unic-emoji-char` seems to have data tables only up to Unicode
-        // 5.0, but Unicode is already newer than this.
-        if unic_emoji_char::is_emoji(self.first()) {
-            contains_emoji = true;
-        } else {
-            // Skip the literal contents.
-            // First symbol can be a number (which isn't a valid identifier start),
-            // so skip it without any checks.
-            self.bump();
-        }
-        self.eat_while(|c| {
-            if is_id_continue(c) {
-                true
-            // FIXME(#108019): `unic-emoji-char` seems to have data tables only up to Unicode
-            // 5.0, but Unicode is already newer than this.
-            } else if unic_emoji_char::is_emoji(c) {
-                contains_emoji = true;
-                true
-            } else {
-                false
-            }
-        });
+        // Skip the literal contents.
+        // First symbol can be a number (which isn't a valid identifier start),
+        // so skip it without any checks.
+        self.bump();
+        self.eat_while(is_id_continue);
 
         // Check if after skipping literal contents we've met a closing
         // single quote (which means that user attempted to create a
@@ -687,7 +664,7 @@ impl Cursor<'_> {
             let kind = Char { terminated: true };
             Literal { kind, suffix_start: self.pos_within_token() }
         } else {
-            Lifetime { starts_with_number, contains_emoji }
+            Lifetime { starts_with_number }
         }
     }
 
diff --git a/compiler/rustc_lexer/src/tests.rs b/compiler/rustc_lexer/src/tests.rs
index 670d64fb983..e4c1787f2cc 100644
--- a/compiler/rustc_lexer/src/tests.rs
+++ b/compiler/rustc_lexer/src/tests.rs
@@ -235,7 +235,7 @@ fn lifetime() {
     check_lexing(
         "'abc",
         expect![[r#"
-            Token { kind: Lifetime { starts_with_number: false, contains_emoji: false }, len: 4 }
+            Token { kind: Lifetime { starts_with_number: false }, len: 4 }
         "#]],
     );
 }
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index e41d0f7047b..9e856c9f212 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -223,21 +223,16 @@ impl<'a> StringReader<'a> {
                     };
                     token::Literal(token::Lit { kind, symbol, suffix })
                 }
-                rustc_lexer::TokenKind::Lifetime { starts_with_number, contains_emoji } => {
+                rustc_lexer::TokenKind::Lifetime { starts_with_number } => {
                     // Include the leading `'` in the real identifier, for macro
                     // expansion purposes. See #12512 for the gory details of why
                     // this is necessary.
                     let lifetime_name = self.str_from(start);
                     if starts_with_number {
                         let span = self.mk_sp(start, self.pos);
-                        let mut diag = self.sess.struct_err("lifetimes or labels cannot start with a number");
+                        let mut diag = self.sess.struct_err("lifetimes cannot start with a number");
                         diag.set_span(span);
                         diag.stash(span, StashKey::LifetimeIsChar);
-                    } else if contains_emoji {
-                        let span = self.mk_sp(start, self.pos);
-                        let mut diag = self.sess.struct_err("lifetimes or labels cannot contain emojis");
-                        diag.set_span(span);
-                        diag.stash(span, StashKey::LifetimeContainsEmoji);
                     }
                     let ident = Symbol::intern(lifetime_name);
                     token::Lifetime(ident)
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 76a2a587911..32bd10f0beb 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -1,6 +1,7 @@
 use std::mem;
 
 use rustc_infer::infer::InferCtxt;
+use rustc_infer::traits::solve::MaybeCause;
 use rustc_infer::traits::Obligation;
 use rustc_infer::traits::{
     query::NoSolution, FulfillmentError, FulfillmentErrorCode, MismatchedProjectionTypes,
@@ -41,13 +42,31 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
         self.obligations.push(obligation);
     }
 
-    fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> {
+    fn collect_remaining_errors(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {
         self.obligations
             .drain(..)
-            .map(|obligation| FulfillmentError {
-                obligation: obligation.clone(),
-                code: FulfillmentErrorCode::CodeAmbiguity,
-                root_obligation: obligation,
+            .map(|obligation| {
+                let code =
+                    infcx.probe(|_| match infcx.evaluate_root_goal(obligation.clone().into()) {
+                        Ok((_, Certainty::Maybe(MaybeCause::Ambiguity), _)) => {
+                            FulfillmentErrorCode::CodeAmbiguity { overflow: false }
+                        }
+                        Ok((_, Certainty::Maybe(MaybeCause::Overflow), _)) => {
+                            FulfillmentErrorCode::CodeAmbiguity { overflow: true }
+                        }
+                        Ok((_, Certainty::Yes, _)) => {
+                            bug!("did not expect successful goal when collecting ambiguity errors")
+                        }
+                        Err(_) => {
+                            bug!("did not expect selection error when collecting ambiguity errors")
+                        }
+                    });
+
+                FulfillmentError {
+                    obligation: obligation.clone(),
+                    code,
+                    root_obligation: obligation,
+                }
             })
             .collect()
     }
diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
index b42a49eb47b..28967e1cc55 100644
--- a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs
@@ -40,13 +40,16 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
         self.obligations.insert(obligation);
     }
 
-    fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> {
+    fn collect_remaining_errors(
+        &mut self,
+        _infcx: &InferCtxt<'tcx>,
+    ) -> Vec<FulfillmentError<'tcx>> {
         // any remaining obligations are errors
         self.obligations
             .iter()
             .map(|obligation| FulfillmentError {
                 obligation: obligation.clone(),
-                code: FulfillmentErrorCode::CodeAmbiguity,
+                code: FulfillmentErrorCode::CodeAmbiguity { overflow: false },
                 // FIXME - does Chalk have a notation of 'root obligation'?
                 // This is just for diagnostics, so it's okay if this is wrong
                 root_obligation: obligation.clone(),
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 6ebf056f0e8..5b49684cfce 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -125,6 +125,8 @@ pub trait TypeErrCtxtExt<'tcx> {
             + Print<'tcx, FmtPrinter<'tcx, 'tcx>, Output = FmtPrinter<'tcx, 'tcx>>,
         <T as Print<'tcx, FmtPrinter<'tcx, 'tcx>>>::Error: std::fmt::Debug;
 
+    fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed;
+
     fn report_fulfillment_errors(&self, errors: &[FulfillmentError<'tcx>]) -> ErrorGuaranteed;
 
     fn report_overflow_obligation<T>(
@@ -602,6 +604,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
         );
     }
 
+    fn report_overflow_no_abort(&self, obligation: PredicateObligation<'tcx>) -> ErrorGuaranteed {
+        let obligation = self.resolve_vars_if_possible(obligation);
+        let mut err = self.build_overflow_error(&obligation.predicate, obligation.cause.span, true);
+        self.note_obligation_cause(&mut err, &obligation);
+        self.point_at_returns_when_relevant(&mut err, &obligation);
+        err.emit()
+    }
+
     fn report_selection_error(
         &self,
         mut obligation: PredicateObligation<'tcx>,
@@ -1658,9 +1668,12 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
             FulfillmentErrorCode::CodeProjectionError(ref e) => {
                 self.report_projection_error(&error.obligation, e);
             }
-            FulfillmentErrorCode::CodeAmbiguity => {
+            FulfillmentErrorCode::CodeAmbiguity { overflow: false } => {
                 self.maybe_report_ambiguity(&error.obligation);
             }
+            FulfillmentErrorCode::CodeAmbiguity { overflow: true } => {
+                self.report_overflow_no_abort(error.obligation.clone());
+            }
             FulfillmentErrorCode::CodeSubtypeError(ref expected_found, ref err) => {
                 self.report_mismatched_types(
                     &error.obligation.cause,
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 07e31e87bfb..26cadab3e9f 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -133,8 +133,15 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentContext<'tcx> {
             .register_obligation(PendingPredicateObligation { obligation, stalled_on: vec![] });
     }
 
-    fn collect_remaining_errors(&mut self) -> Vec<FulfillmentError<'tcx>> {
-        self.predicates.to_errors(CodeAmbiguity).into_iter().map(to_fulfillment_error).collect()
+    fn collect_remaining_errors(
+        &mut self,
+        _infcx: &InferCtxt<'tcx>,
+    ) -> Vec<FulfillmentError<'tcx>> {
+        self.predicates
+            .to_errors(CodeAmbiguity { overflow: false })
+            .into_iter()
+            .map(to_fulfillment_error)
+            .collect()
     }
 
     fn select_where_possible(&mut self, infcx: &InferCtxt<'tcx>) -> Vec<FulfillmentError<'tcx>> {